Skip to main content

Expressiveness Contract — API exposure plan (Task #4)

Lift render-node’s AGENT_EXPRESSIVENESS_CONTRACT.md (§1–§6, on render-node main = production) into the public API so agents can author everything the engine renders. Production runs the C++ engine only — the contract’s “Rust path: warn-skip” deltas do not gate exposure, so capabilities advertise the full contract flat (no engine-aware lower bound).

The pipeline (every feature moves these together)

Verification

  • Unit: schema accepts; translator emits the contract’s exact field names/values.
  • Golden payloads: render-node:tests/mainTests/ReferenceVideoExitTests.cpp holds the exact engine JSON for the 4 target scenes — assert translator output matches it.
  • Pixel parity (follow-up): drive render-node’s headless runner + probe frames (needs Task #3’s runner; not wired yet — noted so it isn’t mistaken for done).

Phase status

Phase 1 — §1 common transform/looks

  • Blend modes — enum 10→17 (separable + W3C non-separable); BLEND_MODE_MAP → camelCase; un-rejected; emitted on video/text/sticker/progress/audioViz.
  • Perspective tiltrotation:{x,y,z} object on video/sticker (overrides scalar); un-rejected.
  • maskShape (circle/diamond/hexagon/star/heart/triangle) — analytic SDF mask on all visual elements
  • backdropBlur — frosted-glass panel (radius px) on all visual elements; shared _common_visual helper
  • [~] nested shadow/border already emitted; per-corner cornerRadius object deferred (uniform works)
  • full filters grade — +temperature/tint/vibrance/highlights/shadows on video+sticker

Phase 2 — new element kinds → milestone: 4 exit-test scenes authorable

  • gradients[] (§5e — golden-payload verified) · [x] groups[] + stack layout (§5) · [x] shapes[] SVG path/stroke/morph/trim (§5b — golden-verified)

Phase 3 — §4 text + §3 animations

  • per-word style (W3 — golden-verified, completes the 4-scene milestone) · [x] range selector (W2) · [x] value counter · textWrap/[x]glow/RTL
  • audio generators · [x] customAnimations registries · loop/calculateTimings (present) · [x] keyframed effect intensity (§2)

Phase 4 — §5c/5d expressive ✅

  • speed ramps (playbackRateKeyframes) · motion blur (params.motionBlur) · track mattes (matte) · animated masks (mask+maskKeyframes)

Phase 5 — §6 canvas + §2 tail ✅

  • background.gradient · aurora + generic effect props · W3 transitions (whipPan/cinematicZoom/burnEdge/shatter/domainWarp) · watermark
  • chroma_key: already exposed via chroma_settings (HSV); the newer keyR/keyG/keyB YCbCr path deferred (verify before touching working code)

Phase 6 — consolidation

  • capabilities completeness audit (verified: 7 element kinds, 17/17 blend modes, aurora, W3 transitions, gradient/shape fields — all advertised, CI-enforced by test_capabilities)
  • SDK version bump 0.1.0 → 0.2.0
  • Remaining (infra-blocked / decisions): elements reference docs; deprecate flat legacy fields (breaking — needs SemVer decision #2); render-parity CI gate needs the headless runner (Task #3) — interim coverage is golden-payload assertions against ReferenceVideoExitTests.cpp

Status: Phases 1–5 complete; Phase 6 audit + version bump done. ~22 commits, full suite 1091 pass.

Open API-design decisions

  1. Groups public shape — top-level groups[] on RenderRequest (matches engine) vs element-nesting sugar.
  2. Legacy field migration — deprecate-and-map the flat x_rotation/border_radius-px fields, or keep both (SemVer impact on SDK)?
See memory: exposure-catch-up-task, api-engine-capability-drift, render-node-main-is-production.