Step 2 of docs/frame-selection.md, which f7e16e5 planned and left unbuilt: the
preserve-snap, and nothing of the plate side. `pose/snapped-frame` is the whole
rule — the latest mark in `(lo, hi]`, and `hi` when there is none — where `hi`
is the native frame the slot defaults to and `lo` is the one the slot before it
defaulted to. So the interval is exactly the frames this slot is the first to
cover, which are exactly the ones the grid shows to nobody: it recovers a
dropped frame out of its own gap, can never read a frame another slot already
showed, and cannot reach past `hi`.
Backward only. A closure at native 13 in a 12-from-30 output is recovered by the
slot whose default is 15, reading 13 — not by the slot at 12 reaching forward,
which would show the mouth shut 17ms before it did and break the no-lead
invariant `cadence_test` asserts over every grid and native pair. That test now
covers the snap too.
Seated as the DEFAULT pose that `pose/source-frame` reaches, so an explicit hand
cut beats a snap with nothing having to say so, and per pose group rather than
at the slot: snapping where the grid becomes native is one frame for the whole
picture, so a head would go two frames stale to fix one mouth. Groups exist only
in `symbol/base-channel-frame`, which is why the interval is threaded that far
down — `(:pre parent)` carried beside `(:f parent)` through the same time maps,
so an ancestor's exposure fold or retime is already in it.
The marks are the `[:vis]` cuts `flow/freeze` already stores, with their
thresholds and hysteresis already decided: no new signal, no new stored field.
A whitelist of `:roto/mouth-aperture` and `:roto/blink` and not a test for
`:generated`, because a skipped frame, a hidden feature and an absent
measurement are three different facts — snapping onto the frames a teeth contour
happened to be missing on is the cadence being dragged about by an absence.
Off is the default and needs no second code path: an opts map that says nothing
gets the behaviour it got before the snap existed. `:snap` is asked about the
SYMBOL, because the cuts are the face's own nodes' and every placement of one
face has the same ones.
The switch is `performance · <face>` in the inspector, and the readout says it
is the stage only. The document setting docs/frame-selection.md specifies wants
a leaf and a round trip of its own; until then this is `[:ui :smart]`, not
undoable, not synced, and unable to reach an export.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
37 lines
2.2 KiB
Markdown
37 lines
2.2 KiB
Markdown
# Time selection
|
|
|
|
Project `:fps` is the playback and export grid. Each symbol has its own native
|
|
`:fps` and `:frames`; keys, spans, trace choices and corrections stay in that
|
|
native space. A symbol without an explicit rate inherits the document rate;
|
|
changing project fps first records that rate so its existing timing stays put.
|
|
|
|
An output frame selects the latest native frame at or before its time:
|
|
`floor(output-frame * native-fps / output-fps)`. Thus 30fps content in a 12fps
|
|
project reads source frames 0, 2, 5, 7, 10… and retains its duration. A partial
|
|
last output frame is included. Changing back to 30 restores the original grid.
|
|
Nothing rewrites or discards the dense measurements.
|
|
|
|
The same boundary selection runs when entering a placed symbol. Placement and
|
|
artistic speed are applied before selection; the stored `:time :rate` and
|
|
`:playback :speed` never contain a frame-rate conversion. The derived maps used
|
|
by timeline rows, picking and editing account for the units of each symbol.
|
|
`clip/frames` is a native length; `clip/output-frames` is a transport/export
|
|
length. Resolver frame queries return native frames for edits.
|
|
|
|
There is one fps control. The old transient picture-fps control and node
|
|
sample-fps fields are gone. Existing exposure, trace choices and per-instance
|
|
pose tracks remain available: a pose track can hold a chosen closed-mouth frame
|
|
without deleting its neighboring measurements. Those choices stay in native
|
|
frames when output fps changes. Automatic content-aware frame selection is not
|
|
implemented; [frame-selection.md](frame-selection.md) is how it should be. An
|
|
event between output frames appears on the next output frame; it cannot create
|
|
an extra frame in a 12fps output.
|
|
|
|
Audio uses continuous time through the same derived placement maps, without
|
|
picture floors or holds. Frame-rate units cancel before Web Audio playbackRate
|
|
is set, so only deliberate speed changes affect pitch and duration. Export and
|
|
playback use the same output count and resolver.
|
|
|
|
Earlier imports with frame-rate conversion baked into stored retimes must be
|
|
re-imported. There is no second reader for that representation. Source video
|
|
presentation timestamps are still future work; this model assumes constant fps.
|