# Trans-Temporal Express — Developer Implementation Guide > **For: AI Development Agent** > **From: UX Design Agent** > **Status: All visual assets generated. Audio files need sourcing. Ready for implementation.** --- ## 1. Vision & Experience Summary You are re-skinning the "AI Time Machine" — a voice-to-voice conversation app where users travel to different historical/future eras and have live conversations with AI-generated characters. The current UI uses a dark steampunk/industrial theme with concentric rings and abstract portals. **You are replacing it entirely** with a warm, whimsical "train cab" experience called **"The Trans-Temporal Express."** ### The Core Metaphor The user is the **engineer** of a magical time-traveling locomotive. They sit inside the cab, look out through a large arched windshield, pull a brass throttle lever, and hurtle through time — watching era signs fly past — until they brake at a destination. Steam clears to reveal the world, and a historical character walks up to the window for a voice conversation. ### Art Style Warm, polished cartoon illustration — like a high-quality animated film. NOT photorealistic. Think Studio Ghibli meets Art Deco. Color palette: warm browns, amber brass, copper accents, cream text, cyan holographic accents. ### Reference Image See `docs/images/Gemini_Generated_Image_6eqvyh6eqvyh6eqv(1).png` — this is the approved visual target for the cockpit view. Note the simple warm wood panels, arched window, brass throttle at center, holographic comm screen at bottom-right, and a character visible through the windshield. --- ## 2. What Already Exists (DO NOT REBUILD) The backend is fully functional. You only need to rebuild the **frontend layer** (HTML/CSS/JS). The following work: ### Backend (Leave Untouched) | File | What It Does | |------|-------------| | `app.py` | FastAPI + Gradio mount. Entry point. `/blank` → intro, `/app` → cockpit | | `src/time_machine/ui/handlers.py` | `GradioHandlers` — `launch()`, `send_text()`, `send_audio()`, `bring_souvenir()`, `save()` | | `src/time_machine/ui/view_models.py` | `UiRenderState` — processes events, builds `render_immersive_payload()` JSON | | `src/time_machine/ui/realtime.py` | WebSocket realtime voice — STT/TTS pipeline | | `src/time_machine/ui/gradio_app.py` | Gradio Blocks layout — **you WILL modify this** to inject new HTML/CSS/JS | | `src/time_machine/domain/models.py` | Domain models (Destination, Persona, ImmersiveScene, etc.) | | `src/time_machine/application/` | Service layer — encounter orchestration, image gen, TTS | ### Key Communication Pattern The frontend receives state via a hidden Gradio `Textbox` with `elem_id="tm-immersive-payload"`. The JavaScript polls this every 750ms via `currentPayload()` and calls `updateCockpitState(payload)` to update the DOM. **The payload JSON structure** (from `render_immersive_payload()` in `view_models.py`): ```json { "session_id": "...", "encounter_id": "...", "machine_state": "dormant|launching|destination|persona|conversation_ready", "current_year": 2026, "target_year": 1492, "direction": "rewind|fast_forward|hold", "destination": { "place": "Port of Palos, Spain", "mode": "past", "atmosphere": "Salt-stung harbor at dawn...", "visual_preset": "harbor_dawn", "motifs": ["wooden_ships", "compass_roses"] }, "persona": { "name": "Isabella", "role": "Harbor master's daughter", "situation": "Watching strange ships being loaded..." }, "scene": { "image_b64": "...", "prompt": "...", "ambient_key": "ocean" }, "portrait": { "image_b64": "...", "prompt": "..." }, "narration": { "text": "...", "audio_path": "data:audio/wav;base64,..." }, "artifact": { "title": "...", "kind": "...", "image_b64": "..." }, "ambient_key": "ocean" } ``` ### Realtime Voice (Leave Untouched) The voice system connects via WebSocket at `/realtime/voice`. The existing `cockpit.js` handles: - Microphone capture → PCM audio → WebSocket - WebSocket → PCM playback (character voice) - JSON control messages for turn management - VAD (Voice Activity Detection) with configurable thresholds **You must preserve the realtime voice section of cockpit.js** (the `initRealtimeVoice()` IIFE starting at ~line 509). The UI just needs the toggle button and status display wired up. --- ## 3. What You Need To Build ### 3A. Intro Sequence (replaces `intro.html` + `intro.css` + `intro.js`) **Current**: A 32-second industrial facility walkthrough (corridors, vault doors, observatory clock). Too dark/sterile. **New**: A ~20-second magical ticket-punching sequence: | Beat | Duration | Visual | Audio | Assets | |------|----------|--------|-------|--------| | **1. Ticket Appears** | 0–6s | Dark void. A brass "Temporal Ticket" materializes, floating center-screen with a gentle glow and slow rotation | Low procedural hum (Web Audio oscillator) | `static/img/intro/temporal_ticket.png` | | **2. Conductor Box** | 6–11s | An ornate mechanical conductor box appears. Ticket slides into it. Flash of light on punch. Gears begin to grind. Energy lines ripple outward | `ticket_clang.mp3`, `charge_up.mp3`, `gears_grinding.mp3` | `static/img/intro/conductor_box.png`, `static/img/overlays/energy_lines.png` | | **3. Train Materializes** | 11–18s | Shockwave explosion of golden energy. The Trans-Temporal Express materializes through the energy — fading from transparent to solid. Train whistle sounds. Steam billows | `shockwave.mp3`, `materialize.mp3`, `train_whistle.mp3`, `steam_burst.mp3` | `static/img/intro/train_materialization.png`, `static/img/overlays/spark_particles.png` | | **4. Board the Train** | 18–22s | Screen flashes white, then fades into the cockpit view. Transition to `/app` | Flash transition (CSS) | None — redirect to cockpit | **Skip button**: Preserve the existing skip-intro button behavior (click or 32s timeout → redirect to `/app`). **Intro HTML/CSS**: Build entirely new. The current corridor/vault/clock HTML is not reused. --- ### 3B. Cockpit View (replaces `cockpit.html` + `cockpit.css` + cockpit portions of `cockpit.js`) **Current**: Dark steampunk portal with concentric rings, timeline bar, separate portrait aperture. **New**: First-person train cab with arched windshield. Reference: `docs/images/Gemini_Generated_Image_6eqvyh6eqvyh6eqv(1).png` #### DOM Structure ``` #tm-cockpit (full viewport container, carries state classes) ├── .tte-viewport (z:10 — windshield content area) │ ├── .tte-idle-bg (idle_viewport.png — default tracks-to-sky) │ ├── .tte-travel-bg (travel_future.png or travel_past.png — during travel) │ ├── .tte-world-scene (#tm-world-image — AI-generated destination) │ ├── .tte-character (#tm-portrait-image — AI-generated character) │ └── .tte-era-signs-container (dynamically spawned HTML signs) ├── .tte-overlays (z:50-90 — effect layers) │ ├── .tte-speed-lines (speed_lines.png, mix-blend-mode:screen) │ ├── .tte-energy-lines (energy_lines.png, for materialization) │ ├── .tte-steam-cloud (steam_cloud.png, for landing reveal) │ ├── .tte-vignette (CSS radial-gradient, always on) │ └── .tte-film-grain (CSS SVG noise, always on, very subtle) ├── .tte-cockpit-frame (z:100 — the cab interior frame) │ └── Built with CSS gradients (see approach below) ├── .tte-dashboard (z:110 — bottom dashboard) │ ├── .tte-gauges (gauge_cluster.png — bottom-left) │ ├── .tte-throttle (chrono_throttle_neutral.png — bottom-center) │ └── .tte-comm-screen (comm_screen.png — bottom-right) ├── .tte-year-module (z:130 — top center) │ ├── .tte-year-label ("DESTINATION") │ └── .tte-year-counter (#tm-year-counter — animated year display) ├── .tte-narration (#tm-narration-caption — bottom text overlay) ├── .tte-live-voice (voice toggle button + meter + status) ├── #tm-narration-audio (hidden audio element) ├── #tm-ambient-audio (hidden audio element) └── #tm-artifact-panel (artifact display, preserved from current) ``` #### Cockpit Frame Approach (IMPORTANT) **Do NOT use cockpit_frame.png as the main frame.** Instead, build the frame with CSS gradients: ```css /* Top arch shadow */ radial-gradient(ellipse 120% 30% at 50% 0%, #2A1810 0%, transparent 70%), /* Left panel */ linear-gradient(90deg, #2A1810 0%, transparent 12%), /* Right panel */ linear-gradient(270deg, #2A1810 0%, transparent 12%), /* Bottom dashboard */ linear-gradient(0deg, #1A0F08 0%, #2A1810 15%, transparent 35%) ``` Add a brass trim border using `::after` pseudo-element with a rounded top border-radius. This gives full flexibility for responsive layouts and the windshield transparency. #### State-Driven CSS Classes The cockpit element `#tm-cockpit` should have these state classes (same pattern as current code): | State | Class | Visual | |-------|-------|--------| | Dormant | `.tm-state-dormant` | Idle viewport visible, throttle neutral, gauges calm, launch pulse | | Launching | `.tm-state-launching` | Throttle rotates, charge-up effect, energy builds | | Traveling | `.tm-state-traveling` | Travel bg visible, speed lines rotating, screen shake, era signs flying, year counter animating | | Braking | `.tm-state-braking` | Violent shake, sparks, speed lines intensify | | Destination | `.tm-state-destination` | Steam cloud covers viewport | | Persona | `.tm-state-persona` | Steam clears, world image visible | | Conversation Ready | `.tm-state-conversation-ready` | World + character visible, cockpit frame dimmed, character breathing animation, ambient audio | --- ### 3C. Travel Sequence (NEW — no current equivalent) When the user clicks "Launch" and the backend starts processing, you need to show a travel animation. Map the `machine_state` transitions to the visual sequence: 1. **`launching`** → Throttle rotates to PAST or FUTURE (based on `direction`). Charge-up SFX. 2. **Wait ~2s** → Transition to travel animation (CSS-driven) 3. **`destination`** → Era signs start flying. Speed lines activate. Year counter animates from `current_year` → `target_year`. Travel background visible. 4. **When world image arrives** (`scene.image_b64` populated) → Begin braking: violent shake, brake screech SFX. 5. **`persona`** → Steam cloud rises, world image loads behind it. Steam clears. 6. **`conversation_ready`** → Character visible, ambient audio playing, voice channel enabled. #### Era Signs (HTML elements, NOT images) During travel, spawn HTML `
` elements with era names that fly across the viewport: ```html
THE SPACE AGE: 1960s
``` CSS animates them from right-to-left (future) or left-to-right (past). They should have: - Dark green background with brass border - Playfair Display font, cream text, uppercase - Brass post extending downward (::after pseudo-element) - Varying vertical positions (30-60% from top) for depth - Getting faster as travel progresses See `static/css/tte_reference.css` for the complete animation keyframes. #### Year Counter The existing `animateYearCounter()` function in cockpit.js already handles this — keep it. --- ### 3D. Audio System Enhancements #### Current Audio - Procedural ambient via Web Audio API oscillators (keep this as fallback) - Narration audio via `