Releases: kiyeonjeon21/reframe
Releases · kiyeonjeon21/reframe
Release list
v0.6.49
v0.6.48
v0.6.47
v0.6.46 — Spatial query (`sceneGeometry`/`hitTest`) + embedded-editor `player --edit`
Added
Spatial query (sceneGeometry/hitTest) + embedded-editor player --edit
- New core spatial query — the spatial analog of
sceneManifest: wheremanifestanswers
"what can I edit?" (addresses),sceneGeometry(compiled, t)answers "where is it on screen,
and what's under a point?". Returns each node's rotatedcorners+ AABBbounds, group
bounds (union of descendants), and motionPathwaypoints(→timeline.<label>.points).
hitTest(geometry, x, y)→ the topmost node at a point. Pure functions over the DisplayList
(each op already carries its sourceid+ final scene-spacetransform) + canvas-free Inter
advances (textWidth) — noevaluate/DisplayOp change, goldens byte-identical. Exported
from@reframe/core; CLIreframe geometry <scene> [--t <sec>] [--json]. player --edit— an embedded-editor build of the HTML player: no autoplay, seek-driven,
exposingwindow.__reframe = { seek, hitTest, bounds, waypoints, setOverlay, play, pause }+
a host↔iframe postMessage channel.setOverlay(doc)re-runscomposeScene+compileScene
+redraw in-browser, no reload — the live overlay-preview loop, so a dragged node/waypoint
round-trips as a regen-stable overlay patch.--edit-origingatesevent.origin. The default
(no--edit) build is byte-identical. Closes #81.
v0.6.45 — `reframe compose` — emit a composed SceneIR (overlay → IR), for live overlay preview
Added
reframe compose — emit a composed SceneIR (overlay → IR), for live overlay preview
- New verb
reframe compose <scene.ts|.json> --overlay <doc>... [-o out.json] [--json]—
composes overlay(s) onto a base and emits the composed SceneIR (no render). This is the
IR half of the corecomposeScene(verify-overlayis its report half). stdout stays a
bare SceneIR (pipe straight intoplayer/frame); the applied/orphan report goes to stderr.
Non-gating — orphans are reported but the partial IR is still emitted. Base may be a.ts
source or a.jsonIR (composition is a post-compile IR→IR transform). Unblocks a live editor:
manifest --json→ build anOverlayDoc→compose→player, no mp4. --overlayonframeandplayer— compose-then-preview in one step (mirrors
render --overlay):player scene.ts --overlay edits.jsonbuilds an instant interactive HTML
with the edit applied;frame scene.ts --overlay edits.jsonrenders a single PNG.compile --overlaynow errors with a pointer instead of silently ignoring the flag
(a footgun fix):compileis source→IR only; composition is a separate transform.- Shared
applyOverlayshelper (packages/render-cli/src/overlay.ts) behind
render/compose/frame/player, so they all compose + report identically. Closes #76.
v0.6.44 — Scene-fitted Kokoro narration (`reframe narrate` + `audio.narration`)
Added
Scene-fitted Kokoro narration (reframe narrate + audio.narration)
- New IR field
AudioIR.narration— spoken voiceover lines ({ at, text, voice? })
authored as a sibling<scene>-vo/script.jsonthe scene imports. Each line resolves to a
label-anchoredfilecue (so VO survives retiming/regen), with a bakedduration
sizing the bed's duck window. Additive + golden-safe (no narration → byte-identical plan). - New command
reframe narrate <scene> [--voice] [--max-speed] [--dry-run]— reads the
compiled label clock, synthesizes each line with a Kokoro python sidecar (narrate.py),
and auto-fits its speech rate to the slot between its anchor and the next line (bounded;
warns if even max speed overruns). Bakesfile/voice/speed/durationback into
script.json(likeassemblebakes ffprobe numbers).--dry-runprints the fit table from
a length estimate with no synthesis. - Kokoro is an optional dependency (
pip install kokoro+ espeak-ng), preflighted like
ffmpeg/chromium. The.wavare external assets (same-machine, not golden) — the determinism
contract still covers the AudioPlan, not the synthesized audio bytes. - Example
examples/scenes/narrated-demo.ts(+narrated-demo-vo/script.json).
v0.6.43 — Structured validation errors (`code` + `path` alongside the message)
Added
Structured validation errors (code + path alongside the message)
SceneValidationErrornow carries.issues: ValidationIssue[]— each problem is
{ code, path, message }with a stable machinecode(unknown-blend,duplicate-node-id,
unknown-timeline-label,bad-duration, …) and apathlocator (nodes.box,
timeline.beat(in)[0],camera.zoom,audio.cues[0]), so a consumer can categorize a
failure and point a UI at the offending element instead of parsing prose.- Propagated in-process:
SceneLoadError.issuescarries them across the scene's own bundled
core (read as a plain property, sinceinstanceofcan't cross the bundle), and
reframe compile --jsonfailures includeissues({ ok:false, error, kind, issues? }).
ValidationIssueis exported from@reframe/coreandreframe-video/compile. - Fully back-compat / additive: every message is byte-identical, and
.problems(string[]).message+ the class identity are unchanged — the existingtoThrow(/…/)suite passes
untouched. Validation isn't on the render path, so goldens are unaffected.
v0.6.42 — Determinism guard — `reframe lint` now enforces scene purity
Added
Determinism guard — reframe lint now enforces scene purity
- Scenes must be pure functions of time (no
Math.random()/Date), but nothing enforced
it: a non-pure scene compiled to a different IR each time, silently breaking
reproducibility (the golden tests only cover IR→render, not source→IR).reframe lintnow
closes that gap for.tssources: it bundles the scene once, evaluates it twice, and
emits anon-deterministic-renderfinding pinned to the first IR address that differs
(e.g.nodes[0].props.x changed 0.42 → 0.97), with a hint at the culprit construct. Part
of the same--strictgate as the addressability checks. - New in-process API
checkDeterminism(path)(exported viareframe-video/compile) →
{ deterministic, findings }, so an embedder can verify a freshly generated scene before
trusting it. Additive: pure scenes report clean, and the check only runs on source inputs
(.jsonis the IR itself). Implementation note: the two evals use distinct cache-busting
comments to defeat Node'sdata:-URL ESM module cache (without which the second eval would
return the cached module and miss module-level nondeterminism).
v0.6.41 — Structural insert — `insertNodes` + `insertTimeline` overlay verbs (Spine 2c)
Added
Structural insert — insertNodes + insertTimeline overlay verbs (Spine 2c)
- Two positioned-insert compose verbs complete the structural-editing CRUD surface
(add / remove / reorder / insert):insertNodes— insert a node at a position (before/aftera sibling root id,
or anindex) instead of appending on top likeaddNodes, so a new layer can land
UNDER later nodes (e.g. a montage shot below the vignette/scrim grade).insertTimeline— splice a step/beat into a named beat ({ into, before/after/index, step }). The step's tween/motionPath targets must exist; unknowninto/before/after
or a missing target is reported as an orphan, never a silent drop.
photoMontage/videoMontagenow group the shot beats directly under the"montage"
beat (the redundant innerseqwrapper is gone — timing-equivalent), so the play order is
addressable:insertTimeline { into: "montage", after: "shot-1", step }splices a shot into
the sequence. Reorder (order) andremoveTimelineare unaffected.- Unlike reorder/remove (which patch existing addressable elements), insert creates
elements, so the overlay carries the full node + beat JSON — a consumer (reframe-studio) or
the author supplies it; reframe does not generate the montage shot payload. See
examples/overlays/montage-insert.jsonanddocs/guides/regen-contract.md.
v0.6.40 — Structural montage editing — reorder + remove (Spine 2c)
Added
Structural montage editing — reorder + remove (Spine 2c)
photoMontage/videoMontagerewritten so each shot is a SELF-CONTAINED named beat
shot-${i}that owns only its own layer's motion (fade-in ∥ Ken Burns ∥ fade-out). Every
layer now starts atopacity: 0, and adjacent shots overlap by the crossfade via a negative
gapin theseq— no shot references its neighbour anymore. This makes a shot an
independent unit you can reorder, drop, or swap by overlay and survive AI regeneration:- Reorder — the existing beat
orderpatch (timeline.shot-2.order) re-sorts shots. - Remove — a new generic compose verb
removeTimeline: ["shot-2"]splices a beat/step
out of its parent by label; theseqre-accumulates so later shots ripple up and
label-anchored dependents (clipstart, anchored titles) follow. A dropped shot's layer just
stays invisible (it never fades in). - Swap an image — already a plain
nodes.<id>.srcpatch.
- Reorder — the existing beat
removeTimelineis the structural complement of thetimelineretiming patch (parallel to
removeNodes); an unknown label is reported as an orphan, never a silent drop. See
docs/guides/regen-contract.mdandexamples/overlays/montage-restructure.json.- The montage now opens on a fade-up and closes on a fade-out (symmetric → edit-safe). Note:
montage timing shifts slightly (shots overlap by the crossfade); the montage has no golden
snapshot, so this is a behaviour change in the generator output only, not a determinism break. - Every generated montage tween now carries a stable label (
shot-${i}-in/-kbfor the
fade-in / Ken Burns,cross-${i}for a crossfade,shot-${last}-outfor the closing fade)
alongside theshot-${i}beat name, so the motion is fully addressable by an overlay and
reframe lintreports no unaddressable motion on a montage.