← back

DynOSTiC Updates
Feb 7, 2026

So we built our cutscene stack the only reasonable way: as a systems engineering problem wearing a storytelling costume.

Design Constraint: Same Timeline, Everywhere

The core requirement was simple to describe and annoying to implement:

In other words, we wanted the "it worked on my machine" class of bugs to feel lonely.

The roadmap followed thin vertical slices: schema -> validation -> runtime -> tests -> docs. It is less exciting than skipping steps, but dramatically cheaper than emergency debugging after content lock.

We started by making transition behavior explicit: ease and transition are first-class fields, not implied vibes.

Runtime support landed for named transitions: cut, crossfade, and directional wipes. Rust validation and deterministic hashing enforced stable interpretation.

The practical outcome was that two engineers could read the same event and stop arguing about what it "probably" does.

Once transitions existed, timing became the next source of accidental creativity. So we added:

This let transitions run in explicit windows inside event durations. Validation guarded impossible combinations.

Result: fewer magic numbers, fewer accidental instant cuts, fewer post-hoc Slack threads.

Raw event timelines are correct but noisy. Authors wanted "shots," not hand-written repetitive events.

We introduced macro: "shot_sequence": high-level shot definitions compile into deterministic timeline events. Compiler errors include source locations, because "line 1, good luck" is not a UX strategy.

This gave us two wins:

We added keyframe tracks for background and image transform/alpha with per-segment easing. Interpolation remained deterministic, including edge cases.

This phase mattered because visual polish tends to be where determinism goes to retire. Instead, we made motion math explicit and testable.

If an alpha ramp changed, it changed because someone changed it, not because floating point woke up in a mood.

Writers think in seconds. Engines think in ticks. Both are right; neither should be punished.

We added:

Compiler normalization converts seconds to integer ticks with deterministic rules. When both tick and time_seconds are provided, compatibility checks ensure they resolve identically.

This gave non-engineering authors time-based ergonomics without sacrificing runtime determinism.

Two expansion tracks landed:

  1. Audio cues
  1. Post effects

Both tracks include deterministic hashing and field validation.

Why hash post-fx fields? Because "looks different but nobody touched content" is a great way to lose a sprint.

Cine Linter

We added linting for pacing, overlaps, missing assets, and invalid references. It catches mistakes before runtime preview, which is where mistakes become opinions.

Preview Upgrades

We added operator-facing tools directly in preview UI:

This converted timeline debugging from "stare at JSON harder" to "observe system state."

Golden-Frame CI Regression

We wired cinematic visual regression into CI:

So now visual regressions get a binary answer in CI, not a committee review in chat.

The durable pattern was:

  1. Keep runtime primitive and deterministic.
  2. Put expressive authoring in compile-time macros.
  3. Validate aggressively at schema boundaries.
  4. Treat docs and tests as part of the feature, not cleanup.

This preserved flexibility without letting content authoring mutate runtime semantics.

Or in less polite terms: we let authors express intent, but not invent physics.

What This Bought Us

Technically:

Operationally:

Emotionally:

The cinematic stack now supports expressive authoring while remaining deterministic, testable, and CI-gated.

The engine still does not understand metaphor. It does, however, reliably render one.