Files
Vance IngallsandClaude Fable 5.1 96fd064192 feat(cli): --motion-blur flag and hyperframes.json render.motionBlur
The engine's sub-frame motion blur (packages/engine/src/services/motionBlur.ts)
and the producer's route validation had no way in: `RenderConfig.motionBlur`
existed but nothing set it. This plumbs both entry points the After Effects
exporter needs, so a comp's own shutter can drive a render without markup.

- `--motion-blur[=angle[:phase[:samples]]]`; bare asks for the engine's
  defaults, `180:-90:16` sets them. `--no-motion-blur` opts out for one run.
- `hyperframes.json` gains `render.motionBlur`, so a project carries its
  shutter as a default; an explicit flag wins, field by field.
- The option travels the ordinary path -- plan -> RenderOptions ->
  RenderRequestOptions (validated at that boundary, which validateJsonSafeValue
  alone does not cover) -> RenderConfig.
- png capture follows from the option inside the producer
  (resolveCaptureImageFormat); screenshot capture is forced onto the engine
  config in renderLocal, because the sub-frame accumulation seeks the live
  timeline rather than reading one instant's paint records. Without it a
  default auto-GPU render engages drawElement and the engine rejects the
  combination by name.
- Docker forwards the flag in its `=` spelling, since an optional-value flag's
  space form would eat the next container argument.

The e2e test renders the composition twice and checks the blur against the
registry's own AE reference: the shutter window's ends land one frame either
side of the frame time over 16 sub-intervals, which shows up as exactly one
partial-alpha column per sub-interval and no partial columns unblurred.

Docs: the `render` flag table and the `hyperframes.json` section.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 01:27:51 -07:00
..