Skip to content

perf: tighten viewer runtime ownership - #675

Merged
Aymericr merged 2 commits into
mainfrom
perf/threejs-runtime
Aug 18, 2026
Merged

perf: tighten viewer runtime ownership#675
Aymericr merged 2 commits into
mainfrom
perf/threejs-runtime

Conversation

@Aymericr

@Aymericr Aymericr commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Tightens viewer lifecycle and per-frame work without changing the default animation schedule:

  • recursively disposes nested geometry-build resources while preserving cached materials
  • pauses the mounted 3D viewer after hidden 2D-mode initialization completes
  • indexes cabinet flame objects instead of traversing every cabinet subtree each frame
  • reports performance timing from the supplied R3F delta rather than mutating the shared clock

Maintainer follow-ups:

Validation

  • bun run check: 1,670 files clean
  • bun run check-types: 10/10 tasks
  • bun run build: 8/8 tasks
  • focused core/viewer/nodes suite: 1,089 passed, 1 skipped, 0 failed
  • browser smoke on the contributed 1,089-wall fixture: DIRTY 0, six meshes, clean 3D → 2D → 3D transitions, no runtime errors
  • public/private boundary scan: only public editor/core/viewer/nodes code; no auth, environment, hosted-community, project identifiers, or private URLs

Screenshots / screen recording

N/A — lifecycle, disposal, frame-loop, and animation-internal changes; no intentional UI change.

Checklist

  • I have tested this locally with the standalone editor
  • My code follows the existing code style
  • Relevant architecture contracts remain documented
  • This PR targets the main branch

Full demand rendering and shadow dirty-gating remain measurement-gated by the active runtime-performance plan.


Note

Medium Risk
Changes affect the global render loop, geometry disposal, and per-frame cabinet animation; behavior is mostly performance and leak fixes, but incorrect pause/disposal could cause stale visuals or rare GPU resource issues.

Overview
Viewer runtime gains a host-controlled renderPaused prop wired through FrameLimiter so the WebGL context stays mounted but scene frames stop advancing. The editor sets this when the 3D pane is hidden and loading has finished (!show3d && !showLoader), cutting per-frame work in 2D-only mode.

Resource lifecycle introduces disposeObject3DResources to walk a subtree, dedupe geometry/material disposal, and skip materials tagged __pascalCachedMaterial. Geometry rebuilds use it instead of inline disposal; MEP preview ghosts dispose replaced materials when ghostifying and tear down the whole ghost on unmount.

Cabinet flame animation pre-collects flame objects per cabinet (rebuilt when the root or child list changes) instead of traversing every cabinet subtree each frame. animateCabinetFlames now iterates that list and uses continue instead of return, so a throttled flame-jet skip no longer stops pulse/material animation for later flames (covered by new tests).

Perf overlay frame timing reads the useFrame delta argument instead of calling clock.getDelta(), avoiding extra mutation of the shared clock.

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

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ae68c9d. Configure here.

Comment thread packages/nodes/src/cabinet/system.tsx
@Aymericr

Copy link
Copy Markdown
Contributor Author

Maintainer follow-up pushed in d455adf3.

The indexed cabinet-flame loop retained traversal-era return statements. A throttled flame jet could therefore abort animation for every later indexed flame. Those exits are now per-flame continue statements, with a regression covering a throttled jet followed by a pulse.

Validated:

  • bun run check
  • full bun run check-types (10/10 tasks)
  • cabinet suite (274 passed)
  • GitHub CI and Bugbot green

The remaining merge gate is the maintainer's local 2D/3D and cabinet-animation smoke.

@Aymericr
Aymericr force-pushed the perf/threejs-runtime branch from d455adf to c76505d Compare August 18, 2026 00:34
@Aymericr

Copy link
Copy Markdown
Contributor Author

Final maintainer gate is complete after rebasing onto #608 and #671.

The overlap composes the two contracts rather than choosing one: FrameLimiter receives maxFps and renderPaused, retains the monotonic synthetic clock across limiter restarts, and keeps the mounted renderer warm while hidden 2D mode stops scene advancement.

Validation on this exact head: Biome checked 1,670 files; 10/10 type tasks passed; 8/8 build tasks passed; 1,089 focused tests passed with one existing skip; the 1,089-wall browser fixture reached DIRTY 0 and six meshes, and switched 3D/2D/3D without runtime errors. The final diff remains entirely in the public editor packages and contains no hosted-community, auth, environment, project, or private-repository material. Remote quality, CLI smoke, and Bugbot are green.

@Aymericr
Aymericr merged commit 570815a into main Aug 18, 2026
3 checks passed
@Aymericr
Aymericr deleted the perf/threejs-runtime branch August 18, 2026 01:22
ovurrsl pushed a commit to ovurrsl/editor that referenced this pull request Aug 20, 2026
Lifecycle, disposal, animation indexing, and frame-loop ownership improvements, validated after composing the wall batching and configurable frame-cap contributions.
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