Skip to content

feat(scenes): loop the ambient preview at 2x by default#44

Merged
karngyan merged 1 commit into
mainfrom
scenes-preview-rate
Jul 25, 2026
Merged

feat(scenes): loop the ambient preview at 2x by default#44
karngyan merged 1 commit into
mainfrom
scenes-preview-rate

Conversation

@karngyan

@karngyan karngyan commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator

Follow-up to #42.

Why

The preview shipped locked to 1x on two arguments. One was taste: a viewer's saved rate is how fast they want to learn, not how fast a teaser should move. The other was technical, and it was wrong.

I assumed a faster loop would desync the stage, with clock-driven phase logic racing ahead while wall-time Motion transitions stayed at their authored speed. Scenes don't work that way. They compute everything from the sequence clock on purpose, because the render path drives them under a fake clock. From GrowIn:

CSS transitions and CSS animations run on the compositor using real wall-clock time, so under the fake clock they either don't progress or snap to the end. Driving the animation from useSceneTime() makes it deterministic in both live and record mode.

So the whole stage scales cleanly with playbackRate. A faster loop is not visually broken, just faster.

With the technical objection gone, the livelier read wins. Double speed also covers the window in half the time, so with the default two cycles a 25s window settles the player in ~25s instead of ~50s.

What

  • Default loop rate is now 2x.
  • preview grows an optional rate for callers who want a different pace.
  • It stays the loop's own rate rather than the viewer's either way, and theirs is still restored on the hand-back.
  • A zero, negative or non-finite rate falls back to the default. Otherwise the clock would freeze at the first frame and the start grace timer would read that as refused autoplay and settle the preview.
type ScenesPreviewOptions = {
  endSeconds: number
  cycles?: number
  rate?: number   // default 2
}

Testing

234 pass (3 changed or new), plus typecheck, lint, format and build.

Covered: the loop runs at 2x while the viewer sits at 1.2x and gets 1.2x back on the hand-back; an explicit rate overrides the default; 0, -1 and NaN each fall back to 2x.

Summary by CodeRabbit

  • New Features

    • Ambient scene previews now loop at 2× speed by default.
    • Added an optional preview speed setting to customize playback rate.
    • Preview timing remains synchronized with scene playback, including faster rates.
  • Bug Fixes

    • Invalid or stalled preview speeds now safely fall back to the default.
    • Viewer playback speed is restored correctly after preview playback ends.

The preview shipped locked to 1x on the theory that a viewer's saved
rate is how fast they want to learn, not how fast a teaser should move,
and that a faster pass would desync the stage: clock-driven phase logic
racing ahead while wall-time transitions stayed at their authored speed.

That second half is wrong. Scenes compute everything from the sequence
clock, deliberately, because the render path drives them under a fake
clock and wall-time CSS transitions either fail to progress or snap to
the end under it. So the whole stage scales cleanly with the rate and a
faster loop is not visually broken, just faster. What remained was
taste, and the livelier read wins: double speed also covers the window
in half the time, so the player settles in half as long.

`preview` grows an optional `rate` for callers who want a different
pace. It stays the loop's own rate rather than the viewer's either way,
and theirs is still restored on the hand-back. A zero, negative or
non-finite rate falls back to the default instead of freezing the clock
at the first frame, which the grace timer would otherwise read as
refused autoplay and settle.
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Ambient preview playback now supports configurable rates, defaults invalid values safely, applies the preview rate independently from the viewer rate, and restores the viewer rate on hand-back. Tests cover these behaviors, and a minor changeset documents the update.

Changes

Ambient preview rate control

Layer / File(s) Summary
Preview rate contract and normalization
src/scenes/provider.ts
preview.rate is added to the public options and normalized state, with positive finite validation and a default rate fallback.
Preview playback and validation coverage
src/scenes/provider.ts, src/scenes/provider.test.ts, .changeset/loud-eels-argue.md
Preview startup applies the normalized rate; tests cover independent preview playback, explicit overrides, invalid values, and viewer-rate restoration. The changeset documents the ambient preview timing updates.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • karnstack/kino#42: Modifies ambient scene preview rate handling and viewer-rate restoration in the same provider and test areas.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main change: ambient scene previews now loop at 2x by default.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch scenes-preview-rate

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
kino 0ac9d57 Commit Preview URL

Branch Preview URL
Jul 25 2026, 10:11 PM

@karngyan
karngyan merged commit 8fd299c into main Jul 25, 2026
5 of 6 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/scenes/provider.test.ts (1)

1201-1211: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover both infinity values in the invalid-rate test.

The normalization contract rejects every non-finite rate, but this test only exercises NaN. Add Infinity and -Infinity so either case cannot regress unnoticed.

Suggested test update
-  for (const rate of [0, -1, Number.NaN]) {
+  for (const rate of [0, -1, Number.NaN, Infinity, -Infinity]) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/scenes/provider.test.ts` around lines 1201 - 1211, Extend the
invalid-rate cases in the test “a rate that would stall the loop falls back to
the default” to include both Infinity and -Infinity alongside the existing
values. Keep the same mountPreviewing setup and assertion that each non-finite
rate posts kino:setRate with the default rate of 2.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/scenes/provider.test.ts`:
- Around line 1201-1211: Extend the invalid-rate cases in the test “a rate that
would stall the loop falls back to the default” to include both Infinity and
-Infinity alongside the existing values. Keep the same mountPreviewing setup and
assertion that each non-finite rate posts kino:setRate with the default rate of
2.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d4f4cdce-6e20-47e6-a48a-e1e16ca0c9b0

📥 Commits

Reviewing files that changed from the base of the PR and between 69d2c44 and 0ac9d57.

📒 Files selected for processing (3)
  • .changeset/loud-eels-argue.md
  • src/scenes/provider.test.ts
  • src/scenes/provider.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant