- 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>
26 lines
1.2 KiB
Python
26 lines
1.2 KiB
Python
"""Auto-director: events -> keyframed camera path (spec M11, lane E). STUB — lane E fills.
|
|
|
|
Contract (frozen at foundation2 merge — phase-5 contract #2): :func:`generate_path`
|
|
returns a **camPath-compatible** dict::
|
|
|
|
{"version": 1,
|
|
"keyframes": [{"t_global": float, "pos": [x, y, z], "quat": [x, y, z, w], "fov": float}]}
|
|
|
|
Poses are **Three.js scene space**, quaternion order **[x, y, z, w]** — convert from the
|
|
COLMAP rows via :func:`festival4d.geometry.colmap_to_threejs`, never inline (pitfall #1).
|
|
|
|
Deterministic v1 rules — no ML: take the top-N events by confidence (ties -> earlier);
|
|
for each, choose the registered camera with a pose nearest the event time; keyframes at
|
|
``t_event - lead_s`` and ``t_event + duration``; when ``config.BEATS_JSON`` exists, snap
|
|
keyframe times to the nearest beat (no beats file -> no snapping — degrade, don't block);
|
|
FOV from that camera's intrinsics (``2 * atan(height / (2 * fy))`` in degrees, the same
|
|
formula as ``scene3d.snapTo``).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
def generate_path(top_n: int = 8, lead_s: float = 2.0) -> dict:
|
|
"""Build a camPath JSON dict from the detected events (see module doc)."""
|
|
raise NotImplementedError("auto-director (lane E / M11)")
|