# 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 `