You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: AGENTS.md
+11-6Lines changed: 11 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -60,20 +60,25 @@
60
60
- The `dive-demo` orientation display example now uses a single `QuickView` canvas with `displayAxes: true`; the previous side-by-side comparison against a manually wired `OrientationDisplay` plugin is no longer the expected snapshot shape
61
61
-`dive-demo` views that gate UI interactivity on `QuickView` readiness, such as `DiveSwitchCanvas` and `DiveTargetAnimation`, need to wait for a non-zero canvas layout plus a small initial delay before constructing `QuickView`; on CI `Linux + xvfb + llvmpipe`, starting too early leaves control buttons permanently disabled
62
62
- In `dive-demo`, replacing the fixed QuickView startup sleep with a shared layout-driven wait helper (`ResizeObserver` plus animation-frame verification) keeps the initial load stable, but canvas-switch flows still need to yield one DOM frame after committing the active-panel state before calling `mainView.setCanvas(...)`
63
-
-`DIVECanvasLifecycleManager` in `src/engine/canvas/` now owns canvas parent observation, renderable-layout bootstrapping, and steady-state resize propagation through one shared `setInterval(..., 16)` bootstrap loop plus one long-lived `ResizeObserver`
64
-
-`DIVECanvasLifecycleManager` now starts its shared 16ms bootstrap lazily directly inside `waitForRenderableCanvas()`; the constructor and `setCanvas()` only reset state and do not start polling on their own
65
-
-`DIVECanvasLifecycleManager.waitForRenderableCanvas()` now owns both bootstrap creation and waiting inline, and falls back to a direct ready-layout read once bootstrap has finished
63
+
-`DIVECanvasLifecycleManager` in `src/engine/canvas/` is again the single owner of canvas readiness state: it keeps the waiter promises, resolves `waitForRenderableCanvas()`, and advances readiness via its own `tick()`
64
+
-`DIVECanvasLifecycleManager.tick()` must early-return while the current canvas remains valid; only invalid, detached, or freshly swapped canvases should re-enter the two-sample stabilization path
65
+
-`DIVECanvasLifecycleManager.tick()` should stay as a shallow entrypoint that does the dispose guard and then delegates the actual lifecycle progression to the private `_checkCanvasHealth()` helper for readability
66
+
-`DIVEView.tick()` should always call `DIVECanvasLifecycleManager.tick()` before honoring the paused/render path so canvas readiness can continue progressing even while rendering is paused
66
67
-`DIVECanvasLifecycleManager` keeps its layout/readiness helpers as private member methods instead of top-level module helpers, so the canvas lifecycle logic stays co-located inside the class
67
68
-`DIVEView.init()`, `DIVERenderer.init()`, and `DIVEEnvironment.init()` should stay `async` and explicitly `await` their cached `_initPromise` values; this repo prefers the consistent async method shape over collapsing those branches to direct promise returns
68
-
-`DIVECanvasLifecycleManager.waitForRenderableCanvas()` can take an optional `AbortSignal`; aborting now only resolves that individual waiter with `null` and removes the waiter listener, while the shared bootstrap interval continues for other callers
69
+
-`DIVECanvasLifecycleManager.waitForRenderableCanvas()` can take an optional `AbortSignal`; aborting resolves only that individual waiter with `null`, while the CLM's shared readiness state keeps progressing through later `tick()` calls
69
70
-`DIVEView` now uses an internal `AbortController` to invalidate pending init work on `dispose()` and `setCanvas()`; even with abort support, `renderer !== this._renderer` remains as the stale-renderer guard after awaited renderer initialization
70
71
-`DIVERenderer` no longer owns DOM/canvas readiness logic; it only initializes WebGPU/environment state, swaps canvases, and handles render/resize calls
71
72
- The old `DIVEResizeManager` compatibility layer has been removed entirely on v3; canvas ownership now lives directly between `DIVEView` and `DIVECanvasLifecycleManager`
72
73
-`DIVEView.setCanvas()` must not force an immediate `onResize()` on the swapped canvas; the `DIVECanvasLifecycleManager` is the single source of truth for resize propagation
73
74
-`DIVECanvasLifecycleManager.setCanvas()` must reset its cached width/height so an equally sized replacement canvas still emits the initial resize sync for the new renderer/camera pair
74
-
- In `DIVECanvasLifecycleManager`, keep raw measurement in `_getCanvasLayout()`; the readiness-gated direct-layout reuse now lives inline in `waitForRenderableCanvas()` because it only has one caller
75
+
- In `DIVECanvasLifecycleManager`, keep raw measurement in `_getCanvasLayout()` and the valid-layout fast path inside `waitForRenderableCanvas()`/`tick()`; there is no longer a separate public readiness accessor
75
76
-`DIVEView` should pass a named `_handleCanvasResize` callback into `DIVECanvasLifecycleManager` instead of an inline lambda, so the renderer/camera resize orchestration stays explicit while the CLM remains decoupled
76
77
-`DIVEView` invalidation branches after async init are best covered by disposing the view while `renderer.init()` is still pending and by invoking the `DIVECanvasLifecycleManager` resize callback directly to assert the `onResize` + immediate render path
77
-
-`DIVECanvasLifecycleManager` coverage is easiest to keep at 100% with fake timers around the shared 16ms bootstrap poll, plus a few explicit private-path tests for aborted waiter signals and direct-layout fallbacks after bootstrap
78
+
-`DIVECanvasLifecycleManager` keeps a single steady-state `ResizeObserver` on the canvas itself; parent changes are handled in `tick()` as validity invalidations rather than as observed resize events
79
+
-`DIVEView` does not inject the clock into `DIVECanvasLifecycleManager`; only `DIVEView` itself is a `DIVETicker`, and `DIVE.startAsync()` must start the `DIVEClock` before awaiting `mainView.init()` so the CLM's internal `tick()` can progress inside the view loop
80
+
-`DIVECanvasLifecycleManager` coverage is easiest to keep at 100% with explicit `tick()` advancement in tests, observer invalidation cases, and signal-based waiter success/stale-resolution assertions
78
81
- In `View.test.ts`, the `waitForRenderableCanvas` mock should be explicitly typed as `Promise<DIVECanvasLayout | null>`; otherwise the stale `null` path triggers a TypeScript error on `mockResolvedValue(null)`
82
+
- In `Dive.test.ts`, `mainView.init` is typed as a plain async method, so tests should narrow it with `vi.mocked(...)` before calling mock-only helpers like `mockRejectedValueOnce` or `mockImplementationOnce`
79
83
- Full focused coverage for `CanvasLifecycleManager.ts` now needs explicit tests for parentless bootstrap polling, renderable-to-zero resets during stabilization, same-size canvas swaps, waiter-only aborts, and the private direct-layout fallback after bootstrap completion
84
+
- Focused single-file coverage in this repo should use `vitest --coverage.include=<path>`; running one suite with the default global `src/**/*` coverage scope still enforces repo-wide thresholds and will fail even when the targeted file itself is at 100%
0 commit comments