Skip to content

Switch from f32 to Duration to measure time#122

Merged
nixonyh merged 12 commits into
mainfrom
nixon/use-duration
Jul 22, 2026
Merged

Switch from f32 to Duration to measure time#122
nixonyh merged 12 commits into
mainfrom
nixon/use-duration

Conversation

@nixonyh

@nixonyh nixonyh commented Jul 21, 2026

Copy link
Copy Markdown
Member

Resolves #115

@nixonyh
nixonyh requested a review from Jaghov July 21, 2026 03:30
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR migrates motiongfx timing from f32 seconds to Duration, adds saturating conversion and offset helpers, updates playback and interpolation, adapts track and timeline APIs, and converts editor and example integrations.

Changes

Duration timing core

Layer / File(s) Summary
Duration conversion and core contracts
crates/motiongfx/src/time.rs, crates/motiongfx/src/action.rs, crates/motiongfx/src/pipeline.rs, crates/motiongfx/src/sequence.rs, crates/motiongfx/src/lib.rs
Duration conversion, action progress, ranges, sequences, and public exports now use duration-based APIs with saturation behavior.
Duration-based track composition
crates/motiongfx/src/track.rs, crates/motiongfx/src/action/table.rs
Track ordering, delays, compilation, empty fragments, duration calculations, and action duration inputs now use Duration and IntoDuration.
Timeline and playback progression
crates/motiongfx/src/timeline.rs, crates/bevy_motiongfx/src/controller.rs, crates/motiongfx/benches/action_storage.rs, crates/motiongfx/examples/custom_world.rs
Timeline advancement, interpolation, realtime and fixed-rate playback, passive playback, benchmarks, and example logging were updated for duration-based timing.
Editor and example integration
crates/motiongfx_editor/..., examples/bevy_examples/..., examples/vello_winit_example/...
Editor controls, Bevy seeking, and elapsed-time looping now explicitly convert or compare Duration values.

Repository hygiene

Layer / File(s) Summary
Finder metadata ignore rule
.gitignore
Adds *.DS_Store to the ignored files.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PlayerController
  participant Timeline
  participant ActionClip
  PlayerController->>Timeline: advance playback or set frame timestamp
  Timeline->>ActionClip: calculate progress at target Duration
  ActionClip-->>Timeline: return normalized progress
  Timeline-->>PlayerController: expose updated current and target time
Loading

Possibly related PRs

Suggested reviewers: jaghov

Poem

I’m a rabbit with clocks in my feet,
Durations make timing precise and neat.
Clips hop from zero to end,
Timelines advance round the bend,
While Finder files vanish from sight!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The .gitignore update for macOS DS_Store files is unrelated to the time-measurement change. Remove the .gitignore change or split it into a separate housekeeping PR if it is needed.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: switching time measurement from f32 to Duration.
Description check ✅ Passed The description is related to the PR and references the linked issue.
Linked Issues check ✅ Passed The changes broadly satisfy #115 by moving time handling to Duration and adding safeguards around timeline and track duration handling.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/motiongfx/src/track.rs (1)

139-149: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

delay() leaves TrackFragment::duration stale after shifting clips.

Every sequence's clips are shifted by delay, but track.duration is never updated to reflect the new (larger) span. The fragment's own test proves this: after delay(1.5, track) on a 2000ms clip, seq_a.end() == ms(3500) but track.duration is asserted to remain ms(2000).

compile()'s max(seq.end(), self.duration) reconciliation (Lines 222-227) masks this for delay(...).compile(), but if the delayed fragment is combined further via ord_chain/ord_flow/etc. before compile(), downstream combinators that read track.duration (as flow() does with other_track.duration, Line 125) will place subsequent clips using the understated span — reproducing the exact duration/clip-offset divergence the code comment above compile() and the chain_accumulation_matches_clip_offsets regression test warn about.

🐛 Proposed fix — mirror flow()'s duration accumulation
 pub fn delay(
     delay: impl IntoDuration,
     mut track: TrackFragment,
 ) -> TrackFragment {
     let delay = delay.into_duration();
 
     for sequence in track.sequences.values_mut() {
         sequence.delay(delay);
     }
+    track.duration += delay;
 
     track
 }

Also update the delay_applies_offset test's expectation from ms(2000) to ms(3500).

🤖 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 `@crates/motiongfx/src/track.rs` around lines 139 - 149, Update delay() to
increase track.duration by the applied delay after shifting every sequence,
matching flow()'s duration accumulation and keeping the fragment span consistent
before compile(). Update the delay_applies_offset test to expect ms(3500)
instead of ms(2000).
🤖 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.

Inline comments:
In `@crates/motiongfx/src/sequence.rs`:
- Around line 38-42: Update Sequence::duration to use a non-panicking duration
subtraction, such as saturating subtraction, so it returns zero when end()
precedes start(). Keep the existing duration calculation unchanged for valid
sequences and retain the current start/end accessors.

---

Outside diff comments:
In `@crates/motiongfx/src/track.rs`:
- Around line 139-149: Update delay() to increase track.duration by the applied
delay after shifting every sequence, matching flow()'s duration accumulation and
keeping the fragment span consistent before compile(). Update the
delay_applies_offset test to expect ms(3500) instead of ms(2000).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 547cce94-70a2-401a-ae3a-167a44e83d60

📥 Commits

Reviewing files that changed from the base of the PR and between 6d4b9fb and b81a6a0.

📒 Files selected for processing (16)
  • .gitignore
  • crates/bevy_motiongfx/src/controller.rs
  • crates/motiongfx/benches/action_storage.rs
  • crates/motiongfx/examples/custom_world.rs
  • crates/motiongfx/src/action.rs
  • crates/motiongfx/src/action/table.rs
  • crates/motiongfx/src/lib.rs
  • crates/motiongfx/src/pipeline.rs
  • crates/motiongfx/src/sequence.rs
  • crates/motiongfx/src/time.rs
  • crates/motiongfx/src/timeline.rs
  • crates/motiongfx/src/track.rs
  • crates/motiongfx_editor/src/lib.rs
  • examples/bevy_examples/examples/slide_basic.rs
  • examples/bevy_examples/src/lib.rs
  • examples/vello_winit_example/examples/lissajous.rs

Comment thread crates/motiongfx/src/sequence.rs

@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)
crates/bevy_motiongfx/src/controller.rs (1)

216-225: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Restore the fluent API returns for PassivePlayer setters.

To maintain consistency with other components (like FixedRatePlayer::set_playing) and prevent breaking downstream builder-pattern usages, consider restoring the fluent return (-> &mut Self) for these setter methods.

♻️ Proposed refactor
     #[inline]
-    pub fn set_time(&mut self, time: impl IntoDuration) {
+    pub fn set_time(&mut self, time: impl IntoDuration) -> &mut Self {
         self.time = time.into_duration();
+        self
     }
 
     #[inline]
-    pub fn set_track_index(&mut self, track_index: usize) {
+    pub fn set_track_index(&mut self, track_index: usize) -> &mut Self {
         self.track_index = track_index;
+        self
     }
🤖 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 `@crates/bevy_motiongfx/src/controller.rs` around lines 216 - 225, Update
PassivePlayer::set_time and PassivePlayer::set_track_index to return &mut Self
after assigning their respective fields, preserving the existing setter behavior
while restoring fluent builder-pattern chaining.
🤖 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 `@crates/bevy_motiongfx/src/controller.rs`:
- Around line 216-225: Update PassivePlayer::set_time and
PassivePlayer::set_track_index to return &mut Self after assigning their
respective fields, preserving the existing setter behavior while restoring
fluent builder-pattern chaining.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d360a20d-6ea1-4ef9-aab0-e6aec535687e

📥 Commits

Reviewing files that changed from the base of the PR and between b81a6a0 and b192237.

📒 Files selected for processing (1)
  • crates/bevy_motiongfx/src/controller.rs

@Jaghov Jaghov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good! just don't see much of a point in the new time module. It could be heavily stripped down if we decide to keep it. Like replacing s() with the impl for IntoDuration for f64 and getting rid of IntoDuration entirely.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not convinced this addition is necessary. I'd rather just have, the api accept a core::time::Duration as an input in the public facing api's or convert from f64 to f32 at the few surfaces users interact with time.

At most, I think the shorthand functions for time could be helpful., but maybe just one shorthand for duration from secs f64.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Hmm, the reason we migrate to Duration is to allow more precise timings. And that's by supporting integer as timings.

Using Duration as the param is fine, but it quickly becomes a hassle to write Duration::new() or Duration::from_secs etc. again and again.

I agree with f32 to f64 is unnecessary I'll fix it with Duration::from_secs_f32.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I'll have a separate PR up for converting our existing examples into using cs, s, and ms more. ns is not really useful in this case, but I'm just keeping it for the sake of completeness.

@Jaghov Jaghov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good!

@nixonyh
nixonyh merged commit 9c25f54 into main Jul 22, 2026
8 checks passed
@nixonyh
nixonyh deleted the nixon/use-duration branch July 22, 2026 15:00
nixonyh added a commit that referenced this pull request Jul 23, 2026
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.

Swap to Duration for meauring time

2 participants