Skip to content

FE-1672: Hold the simulation timeline still while it is off screen - #9656

Merged
kube merged 2 commits into
claude/canvas-firing-visibilityfrom
claude/timeline-holds-still
Sep 11, 2026
Merged

FE-1672: Hold the simulation timeline still while it is off screen#9656
kube merged 2 commits into
claude/canvas-firing-visibilityfrom
claude/timeline-holds-still

Conversation

@kube

@kube kube commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Before this PR, a closed bottom panel was moved off the viewport rather than unmounted, so the simulation timeline went on reading every frame and repainting a chart nobody could see. A stacked chart also re-summed the whole run on every frame to move on by one column.

A timeline that is off screen now stops reading frames and stops drawing until it comes back, and the chart's columns are extended as frames arrive rather than rebuilt from the start of the run.

Scenario Before After
Playback, 200 nodes, panel closed 33 fps 46 fps
Chart repaints, 4 s, panel closed 172 0

Measured against the built website in headless Chromium, driving a ring net through a run, with frame intervals sampled from requestAnimationFrame and repaints counted on the chart canvas.

Before

9656-before.mp4

After

9656-after.mp4

Links

Changes

  • Off-screen timeline stops reading frames and stops drawing

    An IntersectionObserver on the chart's container drives it, so a panel slid away, a scrolled page and a clipped container are all covered.
    The frame cursor is kept, so coming back appends everything that arrived meanwhile in one batch.
    A run reset while the panel is shut is noticed all the same, so reopening does not append the new run to the old one's rows.

  • Chart columns are extended as rows arrive

    A stacked chart re-summed the whole run per frame: 500 series a thousand frames in is half a million additions to move the chart on by one column.
    A run chart allocated a fresh array of gaps per hidden series per frame; every hidden series now shares one that only grows.

  • useElementOnScreen reports whether an element overlaps the viewport

    Starts true and stays true where IntersectionObserver is unavailable, so a caller that gates work on it does that work.

Test coverage

  • chart-data.test.ts:

    Stacking order, hidden series, extension matching a rebuild, and starting over when a run resets.

  • Existing @hashintel/petrinaut unit suite.

How to test

  • Open Petrinaut preview on Vercel
  • Menu > Load example > Supply Chain with Disruption
  • Press Play
  • Close the bottom panel

    Expect playback to run visibly smoother

  • Reopen the timeline

    Expect the chart to show the whole run, including the frames computed while it was shut

  • Timeline header > Stacked

    Expect stacked bands to match the run chart's totals

@kube kube self-assigned this Sep 11, 2026
@vercel

vercel Bot commented Sep 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
hash Ready Ready Preview Sep 11, 2026 3:48am UTC
petrinaut Ready Ready Preview Sep 11, 2026 3:48am UTC
petrinaut-docs Ready Ready Preview Sep 11, 2026 3:48am UTC
1 Skipped Deployment
Project Deployment Actions Updated
hashdotdesign-tokens Ignored Ignored Preview Sep 11, 2026 3:48am UTC

Request Review

@github-actions github-actions Bot added area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team labels Sep 11, 2026
@kube
kube added this pull request to stack #9657 September 11, 2026 00:21
@kube
kube force-pushed the claude/timeline-holds-still branch from 9f36f62 to 43755e4 Compare September 11, 2026 02:05
@kube
kube marked this pull request as ready for review September 11, 2026 02:05
Copilot AI balanced review requested due to automatic review settings September 11, 2026 02:05
@cursor

cursor Bot commented Sep 11, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
UI performance optimization in the timeline panel with conservative fallbacks when IntersectionObserver is missing; behavior when visible should match prior behavior with catch-up on reopen.

Overview
Off-screen simulation timelines no longer burn CPU on closed bottom panels that stay mounted but moved off the viewport. A new useElementOnScreen hook (IntersectionObserver) drives paused on useStreamingData and UPlotChart, so frame reads and uPlot updates stop until the panel is visible again; the processed-frame cursor is preserved and simulation resets are still handled while paused.

Chart data building is incremental instead of recomputing the full run every frame: createRunDataBuilder / createStackedDataBuilder extend columnar data as rows arrive (shared gap column for hidden series in run mode; incremental stacked sums). chart-data.test.ts covers stacking, hidden series, extension vs rebuild, and run resets.

Simulation docs note that closing the timeline stops work until reopen.

Reviewed by Cursor Bugbot for commit b923f68. Bugbot is set up for automated code reviews on this repo. Configure here.

Copilot AI 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.

🟢 Approval recommended

The visibility gating, incremental data handling, tests, documentation, and changeset are consistent and complete.

Pull request overview

Pauses off-screen Petrinaut timelines and incrementally extends chart data to reduce unnecessary work.

Changes:

  • Gates frame reads and chart redraws using viewport visibility.
  • Adds incremental run and stacked-data builders with tests.
  • Updates simulation documentation and release notes.
File summaries
File Description
use-streaming-data.ts Adds resumable frame-stream pausing.
content.tsx Pauses hidden simulation timelines.
chart.tsx Skips paused updates and uses incremental builders.
chart-data.ts Implements incremental chart-data construction.
chart-data.test.ts Tests builder behavior and resets.
actual.tsx Pauses hidden actual-execution timelines.
use-element-on-screen.ts Adds viewport intersection tracking.
docs/simulation.md Documents closed-panel behavior.
.changeset/timeline-holds-still-off-screen.md Records the patch release.
Review details
  • Files reviewed: 9/9 changed files
  • Comments generated: 0
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

A closed bottom panel is moved off the viewport rather than unmounted,
so the timeline went on reading every frame of a run and repainting an
invisible canvas: 172 repaints over four seconds of playback with the
panel shut.

An IntersectionObserver on the chart's container holds both the reads
and the drawing while it is off screen; opening the panel again catches
up in one batch. Closing the panel during a 200-node run now takes
playback from 33 to 46 frames per second.

The chart's columns are also extended rather than rebuilt: a stacked
chart re-summed the whole run on every frame, which on 500 series a
thousand frames in was half a million additions to move the chart on by
one column.
@kube kube changed the title Hold the simulation timeline still while it is off screen FE-1672: Hold the simulation timeline still while it is off screen Sep 11, 2026
@kube
kube added this pull request to the merge queue Sep 11, 2026
Merged via the queue into main with commit c2284ba Sep 11, 2026
89 of 102 checks passed
@kube
kube deleted the claude/timeline-holds-still branch September 11, 2026 15:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

3 participants