[sync2+3] entity mirror seam, SYNC 2 demo + 1080p mp4 verified, M4/polish unlocked
- timeline.js: _mirror — Timeline subscribes stage.onChange, upserts/removes live stage entities into scene.entities (closes the dock-added-entity gap both lanes flagged; keyframing now works without a scene load) - lane files: M2/M3 accepted for all lanes; A→PiP sizing + lady.glb material polish, B→absorb _mirror + test + setDuration mutator, C→M4 (audio mux, graft_limb, MB proxy) SYNC 2: lady+man+street+2cams+sunset built via live dock path, all frame-exact (probes in transcript). SYNC 3: finalRender → 240 frames 1920x1080 → ffmpeg h264 8.000s, cuts + sunset verified in extracted frames. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
dfd4cebd2b
commit
41f2c9fa8d
@ -120,3 +120,20 @@ retargeted clip + timeline scrub, all through the real Stage). Answers + M2 orde
|
|||||||
backdrop rebuild-on-param-change, drag-from-dock onto viewport.
|
backdrop rebuild-on-param-change, drag-from-dock onto viewport.
|
||||||
Test assets now live in `assets/{characters,animations,backdrops}/test/`
|
Test assets now live in `assets/{characters,animations,backdrops}/test/`
|
||||||
(man.fbx, hiphop.fbx, carrying.fbx, street.jpg — gitignored, on ultra).
|
(man.fbx, hiphop.fbx, carrying.fbx, street.jpg — gitignored, on ultra).
|
||||||
|
|
||||||
|
### 2026-07-18 — M2 ACCEPTED, SYNC 2 PASSED. **M3-polish unlocked.**
|
||||||
|
Your entity-mirror seam report was exactly right and well-diagnosed. Resolution:
|
||||||
|
Lane B's Timeline now subscribes to `stage.onChange` and mirrors adds/removes
|
||||||
|
into its model (orchestrator implemented, `timeline.js _mirror`) — your
|
||||||
|
onChange-on-every-add fix is what made that possible; no dedicated
|
||||||
|
entityadd/remove events needed. Verified live: 6 dock-added entities all
|
||||||
|
keyframable, full sunset demo saved as scene `sync2-sunset`.
|
||||||
|
M3-polish list (order):
|
||||||
|
1. **PiP is enormous** — it covered ~70% of the viewport in the SYNC 2
|
||||||
|
screenshot. Cap it (~24% width, bottom-right corner, click to swap
|
||||||
|
director/active-cam views or a size toggle).
|
||||||
|
2. lady.glb (non-mixamo rig, `assets/characters/test/lady.glb`) renders
|
||||||
|
flat white — her textures didn't come through the GLB load path. Check
|
||||||
|
whether it's the asset or a loader/material issue (compare in rigroom).
|
||||||
|
3. Keep `renderActiveCamera`/`pause`/`resume` stable — the finalRender
|
||||||
|
client drives them now (SYNC 3).
|
||||||
|
|||||||
@ -105,3 +105,18 @@ clip retarget playback verified frame-exact via `step()`. Notes:
|
|||||||
6. Injected `<style id=laneB-tl-css>` is fine permanently — keep it.
|
6. Injected `<style id=laneB-tl-css>` is fine permanently — keep it.
|
||||||
Then per plan: crossfade fade-IN polish, params + camera-cut lane UI,
|
Then per plan: crossfade fade-IN polish, params + camera-cut lane UI,
|
||||||
snapping config, box-select multi-drag (undo already wired).
|
snapping config, box-select multi-drag (undo already wired).
|
||||||
|
|
||||||
|
### 2026-07-18 — M2 ACCEPTED, SYNC 2 PASSED. **Session 3 (polish) granted.**
|
||||||
|
Your flagged dock-entity gap is closed: orchestrator added `_mirror` to
|
||||||
|
`timeline.js` (ctor subscribes `stage.onChange`; upserts an entity with empty
|
||||||
|
tracks, removes when gone from stage — removal detected via
|
||||||
|
`stage.getEntity(id) === null`). Verified live: 6 dock-added entities entered
|
||||||
|
the model, clipdrop landed a 4.47s block, sunset param lerp + camera cuts all
|
||||||
|
frame-exact. Session 3 items:
|
||||||
|
1. **Absorb `_mirror`** — review it, then add a timeline_test.mjs case
|
||||||
|
(stub add → mutate → remove; assert entity+tracks lifecycle). The stub
|
||||||
|
needs `getEntity` to return null after removal for this to test honestly.
|
||||||
|
2. Programmatic `scene.duration = x` doesn't refresh the scene bar (only
|
||||||
|
`load()` fires onLoad). Add a `setDuration(x)` mutator that clamps
|
||||||
|
existing keys' visibility and notifies the UI; wire the dur field to it.
|
||||||
|
3. Your listed polish: snapping increment config, keyable-param add UI.
|
||||||
|
|||||||
@ -106,3 +106,21 @@ solid), go straight into §C5 — implement `/render/begin|frame|end|status|out`
|
|||||||
4. uvicorn for local dev: `.venv/bin/uvicorn scenegod.server:app --port 8020`
|
4. uvicorn for local dev: `.venv/bin/uvicorn scenegod.server:app --port 8020`
|
||||||
— there's also a launch entry in MESHGOD/.claude/launch.json ("scenegod")
|
— there's also a launch entry in MESHGOD/.claude/launch.json ("scenegod")
|
||||||
used by the orchestrator's browser preview.
|
used by the orchestrator's browser preview.
|
||||||
|
|
||||||
|
### 2026-07-18 — M2+M3 ACCEPTED, **SYNC 3 PASSED. M4 is UNLOCKED.**
|
||||||
|
Orchestrator ran your `finalRender` end-to-end in the integrated app against
|
||||||
|
Lane A's `renderActiveCamera`: 240 frames @1920×1080 → ffmpeg → out.mp4,
|
||||||
|
h264, exactly 8.000s, with camera cuts and sunset light lerp visible in
|
||||||
|
extracted frames. The browser client path you couldn't exercise is now
|
||||||
|
verified — no changes needed. Proceed with M4 in this order:
|
||||||
|
1. ffmpeg audio mux from scene `audio[]` (the sync2-sunset scene in
|
||||||
|
`scenes/` is your fixture; add a wav to `assets/audio/test/`).
|
||||||
|
2. `scripts/graft_limb.py` (spec in §C6 — blender binary is on ultra's PATH
|
||||||
|
as `blender`; verify with a mixamo body + any rigged hand GLB, and add
|
||||||
|
the refusal-path test).
|
||||||
|
3. `/mb/submit` MODELBEAST proxy last (needs `SCENEGOD_MB=1` gating like
|
||||||
|
riggermore; test only that auth/upload contract matches meshgod/ops.py —
|
||||||
|
don't burn farm jobs on repeat runs).
|
||||||
|
One render-quality note for your backlog, not urgent: draft webm via
|
||||||
|
MediaRecorder is untested in the embedded preview (rAF suspension) — verify
|
||||||
|
it once in a real Chrome window before calling it done.
|
||||||
|
|||||||
@ -99,6 +99,27 @@ export class Timeline {
|
|||||||
if (e.detail && e.detail.id) this.addClipDrop(e.detail);
|
if (e.detail && e.detail.id) this.addClipDrop(e.detail);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// SYNC2 seam: mirror live stage adds/removes into scene.entities so
|
||||||
|
// dock-added entities can be keyframed without a scene load.
|
||||||
|
if (stage && stage.onChange) stage.onChange((en) => this._mirror(en));
|
||||||
|
}
|
||||||
|
|
||||||
|
_mirror(en) {
|
||||||
|
if (!en || !en.id) return;
|
||||||
|
const list = this.scene.entities;
|
||||||
|
const i = list.findIndex((x) => x.id === en.id);
|
||||||
|
if (!this.stage.getEntity(en.id)) { // gone from stage → drop entity + its tracks
|
||||||
|
if (i >= 0) list.splice(i, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (i >= 0) return; // known — timeline already owns its tracks
|
||||||
|
list.push({
|
||||||
|
id: en.id, kind: en.kind, label: en.label,
|
||||||
|
source: en.source ? structuredClone(en.source) : { type: 'upload' },
|
||||||
|
params: en.params ? structuredClone(en.params) : {},
|
||||||
|
transform: this.stage.entityTransform(en.id),
|
||||||
|
tracks: { transform: [], params: [], clips: [] },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get fps() { return this.scene.fps; }
|
get fps() { return this.scene.fps; }
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user