festifun/frontend/src/exportVideo.js
type-two 51650c728e foundation2 (phase 5a): contracts, stubs, hooks & UI wiring for lanes E/F/G
- DB: paths table (contract #3) + helpers; patch_anchor (label/color)
- API: GET /api/beats, POST /api/director (valid-empty degradation),
  /api/paths CRUD (validated POST -> 422), PATCH /api/anchors/{id};
  manifest gains capsule:false (test_api.py key-set lock updated consciously)
- CLI: features | direct | capsule subcommands -> lane stubs (exit-2 degradation)
- Backend stubs with frozen contracts in docstrings: audio_features, director, capsule
- Frontend: six lane stub modules imported from main.js; all phase-5 buttons
  pre-wired hidden in index.html; write-ui/body.capsule read-only mode;
  __F4D_API_BASE__ runtime override in state.js
- Hooks (contract #6): transport.captureAudioStream/releaseAudioStream,
  scene3d.focusOn, scene3d.setHelpersVisible (+registerHelper; camPath gizmos)
- Suite 121 -> 127 passed; npm build clean; live-browser verified (status file)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 17:31:08 +10:00

19 lines
1016 B
JavaScript

// Cinematic export (spec M12, lane E). STUB — lane E fills THIS FILE ONLY.
//
// Pre-wired by foundation2: the hidden ⏺ button (#btn-export in index.html), this module's
// import + init() call in main.js, and the transport hooks
// `transport.captureAudioStream()` -> MediaStream tapping the live WebAudio mix (post-gain,
// spatial included) and `transport.releaseAudioStream()` when done.
//
// When implementing: unhide the button, set `ready = true`; on click seek to the first
// camPath keyframe, play the path, mux scene3d canvas `captureStream(30)` + the audio stream
// with MediaRecorder (video/webm;codecs=vp9,opus), stop at the last keyframe, download
// `festival4d-cut.webm`, then RESTORE all prior UI/transport state. The canvas is
// `scene3d.renderer.domElement`. MediaRecorder needs a *focused* tab to capture real frames
// (pitfall #2) — say so in your evidence if you couldn't.
export const exportVideo = {
ready: false,
init() {}, // ponytail: stub — lane E replaces the body
};