Skip to content

Storyboard time-range Scenes — time_range != null interpolation (pan/zoom + time-slider scrub) #630

Description

@IanMayo

Problem

Today every Scene captured by #216 is a single-instant viewport snapshot (time_range = null per #215). For scenarios where the analytical story is "watch the contact converge over the next 10 minutes" or "show the search pattern unfold", authors have no way to record a time-windowed Scene — they must capture many adjacent single-instant Scenes and rely on the transport's flyTo + slider tween (#217) to suggest motion. The Out of Scope lists in specs/215-storyboarding-schema/spec.md, specs/217-storyboarding-playback/spec.md, and specs/218-storyboarding-edit/spec.md all explicitly defer this as a phase-2 follow-up.

Schema scaffolding is already present: SceneProperties.time_range exists in geojson.yaml and is currently always null. Closing this gap is the natural next step in storyboarding expressiveness.

Proposed Solution

Lift the v1 constraint and make time_range != null a first-class capture + playback mode.

Capture (extends #216):

  • New "Capture range…" affordance (UI shape TBD during /speckit.specify — likely a modifier on the existing Ctrl/Cmd+Alt+C shortcut, e.g. Ctrl/Cmd+Alt+Shift+C, with a small inline prompt to mark the end time by pressing again at the desired moment).
  • Scene's time_range = [t_start, t_end] is stored; viewport is captured at the start and at the end (two viewport snapshots inside the Scene).

Playback (extends #217):

  • Full v2 behaviour confirmed in interview: both pan/zoom interpolation AND time-slider scrub.
  • During executeTransition into a time-range Scene, the playback engine:
    1. Linearly interpolates the viewport from viewport_startviewport_end over the captured wall-clock duration (or a transport-configurable playback rate).
    2. Simultaneously advances the time-slider from t_startt_end so feature visibility / track positions / chart cursors all move in lock-step.
  • Reverse playback (existing transport Backward button) reverses both axes.

Schema:

  • SceneProperties.time_range already exists; add viewport_end: Viewport | null (or model both endpoints as a list).
  • Generate Pydantic / TS / JSON Schema.
  • Article II adherence tests + new golden fixtures for time-range Scenes.

CRUD (shared/components/src/storyboard/):

  • createScene accepts an optional timeRange + viewportEnd.
  • Validation rejects time_range ranges that fall outside the plot's time bounds, or where t_end <= t_start.

Success Criteria

  • An author can record a Scene that plays back as a continuous viewport tween + time-slider sweep over an analyst-chosen window.
  • A Storyboard mixing single-instant and time-range Scenes plays back correctly with each Scene honoured per its time_range shape.
  • Schema round-trip (Python ↔ TS ↔ JSON) passes for time-range Scenes; golden fixtures cover both Scene flavours.
  • Existing single-instant Scenes continue to behave exactly as before (no playback regression).
  • Backward playback reverses both viewport interpolation and time-slider sweep cleanly.

Constraints

Out of Scope

  • Non-linear interpolation curves (ease-in / ease-out / Bézier). Linear only in MVP.
  • Per-Scene playback-rate override. Single global transport rate.
  • Drag-handle UI to scrub the captured range after the fact (edit-time range adjustment). Editing the range is delete + re-capture in MVP.
  • Time-range Scenes inside the air-gapped briefing zip (Refactor map feature selection styling to use CSS classes #264) — captured separately; the briefing renderer absorbs time-range support naturally via the shared playback engine.
  • MP4 / GIF export of time-range Scenes (Spec #055: Track-Position to Track Range/Bearing Tool #265).

Dependencies


Originally captured under epic item #229 in BACKLOG.md; promoted via /interview 229 (2026-05-19) — epic was split into three independent items.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions