128 lines
7.6 KiB
Markdown
128 lines
7.6 KiB
Markdown
# Timing and frame-selection handoff
|
|
|
|
Status (2026-09-29): the multi-face representation is complete. Each face has a
|
|
local drawing timeline and an ordinary symbol instance. Keep that model; the next
|
|
feature is performance-pose selection, followed by plate drawings and tracing.
|
|
See [multi-face representation](multi-face-representation.md) for verification
|
|
and compatibility limits.
|
|
|
|
## Next steps, in order
|
|
|
|
1. **Commit the verified checkpoint.** Representation, scoped regeneration,
|
|
nested stage composition and source persistence are implemented and tested.
|
|
2. **Exercise real two-person footage.** Include crossings, late arrivals and
|
|
disappearances. Assignment is still a nearest-centroid heuristic; inspect
|
|
whether identities, landmarks and mouth crops stay together. Correcting an
|
|
assignment requires measuring again. Do not redesign the representation to
|
|
compensate for an assignment failure.
|
|
3. **Build performance-pose selection.** Propose frames from a target picture
|
|
rate, allow explicit Keep/Drop edits, and apply requests per instance. Reuse
|
|
the existing held-frame lookup and generated pose groups. Keep authored keys
|
|
and audio timing intact.
|
|
4. **Then build plate drawings and tracing.** Suggest drawing frames from head
|
|
displacement, allow manual choices, and give each cel an independently
|
|
selectable tracing reference.
|
|
|
|
Older flat captures need reanalysis for the new regeneration path. Migrating their
|
|
existing authored edits is separate work; it is not implemented by this checkpoint.
|
|
|
|
## Timing decisions
|
|
|
|
Keep the dense analyzed frames. Generated motion holds the most recent selected
|
|
source pose; removing a selected pose never deletes source data or shortens the
|
|
clip. Store edits in the animation's local frame space, so moving an instance
|
|
does not move its edits. Authored keys follow intentional instance retiming but
|
|
must not be quantized by a picture-rate request. Clip FPS and audio duration stay
|
|
fixed.
|
|
|
|
There are two selections with different owners, sharing held-frame lookup:
|
|
|
|
- **Performance poses:** propose a kept-frame list from the target picture rate,
|
|
then apply explicit keep/drop edits. A parent instance may request a lower
|
|
rate. Mouth outline, interior, teeth and visibility read the same selected
|
|
source frame; likewise each eye's coupled parts. Use group overrides when
|
|
needed, rather than a setting on every channel. Head motion currently has its
|
|
own anchor selection; do not silently put it under mouth timing.
|
|
- **Plate drawings:** start with frame 0, walk measured rigid head poses, and
|
|
suggest a frame when maximum landmark displacement from the last kept pose
|
|
exceeds tolerance. Let the artist add/remove frames. A removed drawing stays
|
|
stored so it can reappear if restored. This selection does not thin the mouth.
|
|
|
|
A target rate is approximate. Pin a useful closed-mouth pose at its actual frame,
|
|
even if that produces more changes than the target. Do not show a future pose
|
|
early to fit a grid. Manual drop wins over an automatic suggestion; make removal
|
|
of the only closed pose in a beat visible in the UI. Skip missing detections when
|
|
suggesting a replacement. Keep a frame-zero selection and hold the last selection
|
|
through the end. A skipped pose (hold), `[:vis] false` (hidden), and an absent
|
|
measurement remain different facts.
|
|
|
|
Store manual edits separately from generated proposals so changing the rate or
|
|
tolerance retains hand decisions. Selection edits change the document, not dense
|
|
blocks or analysis addresses. Verify save/open for every new field; extend leaf
|
|
handling and the relevant key whitelist if its storage location requires it.
|
|
|
|
## Current code: reuse these mechanisms
|
|
|
|
- `domain/pose.cljs` already has `prepare`, `held-frame` and `source-frame`.
|
|
Instance `:playback :tracks` map local change frames to held source frames,
|
|
keyed by pose group. Reuse this lookup; frame suggestion and Keep/Drop policy
|
|
are the missing layer. An explicit cut is not itself a complete selection UI.
|
|
- `freeze/performance-nodes` marks generated animated channels with
|
|
`:pose-sampled?` and local `:pose-group` names. This includes keyed visibility
|
|
as well as dense geometry. `:generated` remains provenance for regeneration.
|
|
- `timeline/channel-frame` already applies explicit pose choices and default
|
|
picture sampling to marked channels. Playback and export both use
|
|
`clip/resolver` with `:picture-fps`; there is no need for a second sampling
|
|
implementation. Export's pose count is still a rate-based estimate.
|
|
- The picture-rate option is currently passed through the resolver tree
|
|
unchanged. Instance-specific parent requests are still to be implemented.
|
|
Instance offset/rate must apply before selecting the local source pose.
|
|
- `pose/put-cut` and `remove-cut` currently address instances in `:main`.
|
|
A take's face instances are there, but a composed stage nests them inside a
|
|
shared source timeline. Make the editing scope explicit when adding nested
|
|
controls. A request on one outer placement must not rewrite the shared
|
|
drawing's playback settings for every placement.
|
|
- Generic root `:time :expose` still retimes descendants, and frozen takes still
|
|
store it. Paint nodes are rootless to escape it. When the selection path
|
|
replaces take picture cadence, remove that redundant quantization from the
|
|
take default; preserve intentional generic time maps. Moving exposure to
|
|
`:head` would still retime authored children.
|
|
- `freeze/head-mode` supports `:free` and `:anchored`. It keeps measured channels
|
|
dense and writes optional per-subject `:anchors` maps; it does **not** implement
|
|
`:per-plate` mode or materialize transform keys from `:kept`. Plate selection
|
|
should reuse held measured-frame addresses where appropriate, without
|
|
rerunning analysis or copying the measurements.
|
|
- `:over` hand corrections are currently refused by the channel reader. Their
|
|
future application belongs after generated pose selection.
|
|
|
|
## Performance-pose implementation sequence
|
|
|
|
1. Add pure proposal and Keep/Drop policy around the existing held-frame lookup.
|
|
Cover frame zero, nondivisible rates, manual precedence, missing poses and a
|
|
protected mouth closure. Preserve all source frames.
|
|
2. Feed instance requests and group selections into the existing channel read
|
|
path. Cover two faces, two differently timed placements of one source, nested
|
|
instances, coupled visibility/geometry, and authored keys at their normal time.
|
|
Use this same path for preview and export; keep audio duration unchanged.
|
|
3. Wire the performance strip's Suggest/Keep/Drop controls and persistence.
|
|
Replace the export pose estimate with the actual selection count. Retire the
|
|
take's redundant root exposure only when this path replaces its behavior.
|
|
|
|
## Plate drawings and tracing, afterward
|
|
|
|
The old suggestion algorithm is `js/pipeline.js:suggestPlateFrames`; the strip,
|
|
worksheet and tracing photo are in `js/app.js`. Port the useful policy over the
|
|
measured head poses and reuse held-frame lookup for the resulting drawing set.
|
|
|
|
Give a cel an editor-only source-frame reference, defaulting to its plate frame
|
|
but independently changeable. It may point to a frame omitted from either rendered
|
|
selection. Register the photo using that source frame's measured transform. The
|
|
old prototype coupled photo and cel addresses; independent tracing is new work.
|
|
|
|
The old iris socket lock, gaze origin, CLJS head anchors and registration pivot
|
|
are separate settings. Clarify what an "origin-lock" request means before adding
|
|
that control.
|
|
|
|
Keep the UI to two scopes: **performance poses** and **plate drawings**, each with
|
|
Suggest/Keep/Drop. Tracing reference and lock controls live with the cel or feature
|
|
they affect. No general keyframe framework is needed for this work.
|