
================================================================================

     ____  ___   ___ __  __ ___ ___   ___ _   _ ___ _  _   ____
    / ___|/ _ \ / __|  \/  |_ _/ __| | _ \ | | / __| || | |___ \
   | |   | | | |\__ \ |\/| || | (__  |   / |_| \__ \ __ |   __) |
   | |___| |_| |___) |  | || |\___| |_|_\\___/|___/_||_|  |___/
    \____|\___/|____/|_|  |_|___|

                             a demo by felisuco
                                    CTM
                          Euskal Encounter 34 (2026)
                             PC Demo Competition

================================================================================

  "ZERO POLYS. ZERO SHADERS. NO GL. ONLY CPU."

  183 seconds of pure Python demoscene running on top of pygame and numpy.
  Every triangle, every particle, every pixel is computed on the CPU and
  blitted through SDL2's software renderer. No OpenGL, no compute shaders,
  no fragment shaders — just Python doing what Python was never meant to do.

--------------------------------------------------------------------------------
 QUICK START — RUN THE BINARY
--------------------------------------------------------------------------------

  A single, self-contained Linux executable ships with the demo. No Python
  install required, no pip, no venv — just launch it:

      ./CosmicRush3                    # fullscreen (default)
      ./CosmicRush3 -w                 # windowed 1280x720
      ./CosmicRush3 --seek 90          # jump to second 90 (skips preroll)
      ./CosmicRush3 --hud              # show debug HUD
      ./CosmicRush3 --nomusic          # silent playback
      ./CosmicRush3 --benchmark        # print FPS, no music

  The binary lives at:   dist/CosmicRush3   (~56 MB, ELF x86-64)

  Keys during playback:

      Y / SPACE / ENTER   run the demo from the preroll prompt
      N / ESC / Q         quit (from anywhere)
      F                   toggle fullscreen
      SPACE               pause / resume music (during the demo)
      RIGHT / LEFT        +/- 5 seconds seek shortcut

  System requirements: any modern Linux x86-64 with GLIBC >= 2.17
  (Ubuntu 18.04+, Debian 10+, etc.), ~100 MB free RAM, stereo audio.
  A 1080p or higher display is recommended — the demo renders at
  1280x720 and SDL upscales it.

--------------------------------------------------------------------------------
 THE PREROLL — Another World-style boot sequence
--------------------------------------------------------------------------------

  Before the music starts, a CRT-green boot screen plays for ~12 s:

    * Copyright + version + a personal greeting type themselves out
      character by character (with a mechanical key-click on each key).
    * An old hard drive noise loops in the background.
    * A prompt appears: "RUN EXPERIMENT?      Y"  (blinks).
    * Auto-runs after 5 s, or press Y / SPACE / ENTER to start immediately.
    * N / ESC quits.

  The preroll is skipped automatically when --seek, --nomusic or
  --benchmark are used, so dev iteration stays snappy.

--------------------------------------------------------------------------------
 THE DEMO — 183 seconds, ~10 scenes
--------------------------------------------------------------------------------

    0 - 14 s      ZEN INTRO
                  Three title cards on paper: FELISUCO / IN EE34 VISION /
                  COSMIC RUSH 3 (last one zooms in slowly). Faint pastel
                  starfield, no film grain (kept clean).

   14 - 37.5 s    T O R U S
                  Single torus rotating quietly on the paper background.
                  Reactivity ramps up in the second half.

   37.5 - 51.2 s  SOLIDS RAIN  (subidón)
                  Filled 3D solids rushing toward the camera. Trail kicks
                  in mid-scene. Watermark: "ZERO POLYS / ZERO SHADERS".

   51.2 - 64.5 s  ORBITING SOLIDS
                  Multiple swarms of filled polyhedra orbiting the centre.
                  Mesh alternates on onsets.

   64.5 - 78 s    G L I T C H  reveal
                  Boss solid + satellites orbit in the background while the
                  word "GLITCH" assembles in 3D pixel-art from a scattered
                  cloud of grey particles, rotates, glitches, bursts back
                  into particles.

   78 - 85 s      PORTAL  (audio EQ + rocket)
                  32-band audio equaliser at the bottom, driven by the
                  offline STFT analysis. A procedural rocket launches
                  upward with a bass-reactive flame. Post-fx OFF for
                  a clean look.

   85 - 132 s     TERRAIN FLY-THROUGH  (drop 1)
                  Wireframe -> filled heightmap terrain, camera flying
                  forward. FOUR bouncing Amiga-style Boing Balls (red, cyan,
                  magenta, green) with elastic ball-to-ball collisions.
                  Reflection ceiling in the sky mirrors the terrain below.
                  At 98.5s the terrain EXPLODES outward, revealing:
                     - a starfield warp
                     - AURORA BOREALIS (vertical bands of cyan/green/
                       magenta wobbling with the bass)
                     - vertical credits scrolling upward through the sky
                  At 132.4 s a second explosion shatters the frame into
                  flying pixels.

   139 - 145.6 s  NEBULA breather  (drop 2)
                  Shockwave (white flash + expanding cyan ring) marks the
                  drop. 2000-particle nebula in magenta/violet/cyan/gold
                  with additive trail, swirl + beat-driven radial push.

   145.6 - 173 s  LOCURA FINAL
                  Neon strobe, two orbiting swarms with filled solids,
                  polygonal tunnel behind, particle explosion, crazy-grid
                  overlay, DANCE + C O S M I C R U S H 3 pulsing on every
                  beat. At 159 s the music breaks down: a 32-band EQ
                  visualiser appears along the bottom edge; between 165
                  and 170.6 s a monochromatic red tint takes over everything;
                  then colour returns for the last 2.4 s before the shatter.

   173 - 183 s    Come-down + final title
                  The scene shatters into flying pixels; against the debris
                  the final title fades in: "C O S M I C  R U S H  3" with
                  "See You Space Cowboy..." beneath it (Cowboy Bebop nod).
                  Four seconds of black close the demo.

--------------------------------------------------------------------------------
 THE OUTRO — END OF EXPERIMENT + TV shutdown
--------------------------------------------------------------------------------

  When the music ends naturally (183 s), the music fades out over 2.5 s
  and a symmetric CRT-green epilogue plays:

      END OF EXPERIMENT.

      EXPERIMENT LOG:
        DURATION       : 00:03:03
        BEATS DETECTED : 435
        REALITY CHECK  : STABLE.

      GREETINGS TO ALL SCENERS AT EE34.
      STAY COSMIC.

      felisuco / CTM

      THANK YOU.

  After 3 s a classic CRT power-off animation triggers: the image collapses
  vertically to a bright horizontal line, then to a single point, then
  fades to black with a synchronised electrical pop. Pressing ESC or Q
  during the demo skips the outro and quits cleanly.

--------------------------------------------------------------------------------
 CREDITS
--------------------------------------------------------------------------------

  Code + effects .... felisuco  (with Claude / Gemini / Codex assisting)
  Music ............. MAIKEL 1994  -  "Cosmic Rush 2.5"
  Tools ............. Python 3, Pygame, NumPy, Librosa
  Group ............. CTM  /  Chimuelos Taxidermistas En Motonieve

  Audio attributions (see assets/audio/CREDITS.txt for full details):
    - hdd_rasp.mp3   Michael Vogl, "Hard Drive Noises",
                     CC BY-ND 4.0, https://archive.org/details/hdd-3
    - Fonts:         Michroma, Space Grotesk (Google Fonts, OFL),
                     Noto Sans CJK JP (SIL OFL)

  Version history:
    COSMIC RUSH 1    -  EE33  DEMO
    COSMIC RUSH 2    -  EE34  GAME
    COSMIC RUSH 2.5  -  EE34  SONG
    COSMIC RUSH 3    -  EE34  DEMO   ← this one

--------------------------------------------------------------------------------
 RUNNING FROM SOURCE (developers)
--------------------------------------------------------------------------------

  If you want to run from the Python source instead of the binary:

      ./venv/bin/python main.py                    # fullscreen
      ./venv/bin/python main.py -w --seek 64       # windowed at t=64s
      ./run.sh 138.5                                # helper: seek fullscreen
      ./venv/bin/python tests/smoke.py             # render every scene once

  Regenerating audio_analysis.npz (only if you swap the mp3):

      ./venv/bin/python analyze_audio.py           # skips if .npz is up-to-date
      ./venv/bin/python analyze_audio.py --force   # rebuild anyway

  Rebuilding the single-file binary with PyInstaller:

      ./venv/bin/python -m PyInstaller --noconfirm --clean CosmicRush3.spec
      # → dist/CosmicRush3   (self-contained, ~56 MB)

--------------------------------------------------------------------------------
 TECHNICAL NOTES
--------------------------------------------------------------------------------

  * Music sync is done offline: analyze_audio.py runs librosa once on the
    mp3 and produces audio_analysis.npz with per-frame arrays for RMS,
    32 log-spaced band energies, onset envelope, drop timestamps and
    buildup windows. At runtime AudioTrack.sample(t) just indexes into
    those arrays — no live FFT.
  * Rendering is done into a 1280x720 pygame Surface scaled by SDL to
    the actual display resolution (pygame.SCALED flag).
  * All 3D meshes use back-face culling + painter's algorithm implemented
    in NumPy. No z-buffer. Face normals and shading are computed in
    vectorised bulk per frame.
  * The demo is fully deterministic in t (audio position). You can jump
    to any second with --seek and everything (visuals + music) will be
    in sync.
  * Global post-effects (film grain, vignette, chromatic aberration,
    scanlines) are gated per-scene so calm sections can opt out. Grain
    is silenced during the intro (0-14 s).
  * Boot preroll audio (key clicks, TV pop, beep, HDD-rasp fallback) is
    synthesised on the fly with numpy → pygame.sndarray.

--------------------------------------------------------------------------------
 CONTACT
--------------------------------------------------------------------------------

  felisuco  —  info@justdust.com
  https://justdust.com

--------------------------------------------------------------------------------
 GREETINGS
--------------------------------------------------------------------------------

  To the good people at EE34, and to everyone who still pushes pixels
  one at a time.

  STAY COSMIC.  KEEP CODING.

================================================================================
