Repository navigation
Experimental world-transform camera renderer - #2
Open
DanFessler wants to merge 12 commits into
Open
DanFessler wants to merge 12 commits into
DanFessler wants to merge 12 commits into
Conversation
A view whose content fails to mount (or whose iframe function throws) shows a fallback with its title, the error and Try again, and the rest of the workspace carries on. In React, every view's content, icon and accessory renders inside its own error boundary, so one throwing component no longer unmounts the workspace. Everything that throws, from view code, callbacks, close guards or event listeners, goes to a new error event with its source, view and type; without a listener it goes to the console. ws.reportError sends an app's own errors down the same channel, errorFallback replaces the fallback (core and React, per workspace or per type), and React gets an onError prop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With direction "rtl" (or "auto", the default, on a right-to-left page) the workspace mirrors: a row's first child sits on the right, tabs and menus run right to left, and floating windows are placed from the right. The document stays direction-neutral; the mirror is applied where layout coordinates meet the screen, so dividers, docking, tab reordering, floating resize, collapsed groups and every navigation gesture follow the pointer. Arrow keys follow reading order in tab lists and menus and move dividers the way they point. Key combinations in menus keep reading left to right. React gets a direction prop, the web component a direction attribute. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A permissions option (and React prop) sets what users may change through the interface: rearrange, resize, close, float and hide, each on by default, or false to lock everything. Each one covers every path to its action: drags, dividers and their keys, floating-window edges, close buttons, middle-click, Delete, panel menu items and shortcuts. Locked dividers and resize handles aren't shown. Calls from code are never limited, and permissions can change at any time. Also fixes Close other tabs closing tabs whose type isn't closable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sanitize now trusts nothing about its input: any value at all comes back as a valid document without throwing. Wrong types, nulls, missing or duplicate ids, non-numeric rects, bad restore targets and malformed framings are repaired, with fresh ids rather than lost content. A fuzz test runs 3000 corrupted layouts through it and checks every invariant the workspace relies on. The workspace repairs a document before deciding on unregistered view types, so setDocument accepts anything, and a saved layout with the wrong shape falls back to the default layout. Placeholders for unregistered types are marked view-missing, and their records survive saving until the type is registered. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rendering looked up every view's panel and region by walking the whole layout, for each view on every frame: views × panels work per frame, 30,000 tree visits at 300 views. The workspace now indexes views and panels once per document change. Views in background tabs aren't repositioned while things move, and dividers hide during camera moves as they already do during layout animations. With the CPU slowed 4× and 300 views, slow frames during a tab drag fall from 98% to 3%, during a zoom from 84% to 22%. scripts/bench.mjs measures startup, memory and frame timing for 16, 108 and 300 views, at full speed and slowed 4×, and prints the tables docs/performance.md quotes. The e2e stress scenario takes its grid size from the URL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The built-in icons were parsed from markup, which throws where Trusted Types are enforced, so the workspace couldn't start at all. Collapsed groups drew their lines with inline style attributes, which a policy blocking them leaves unpositioned, and icon-only panels copied their icon by re-parsing its markup. All three now build elements and set positions through the style object. A new e2e scenario runs under style-src-attr 'none' and require-trusted-types-for 'script' and checks icons, menus, collapsed groups and icon tiles, with no violations. Icon markup that an app passes as a string is still HTML, and documented as such. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…erformance, security New guides for handling errors, locking and permissions, and right-to-left layouts; new Performance (measured with npm run bench) and Security pages. Persistence covers damaged and outdated layouts, unknown view types and several layouts per user or team. The API references, theming and keyboard pages cover the new options, events, parts and attributes. The core's size is now quoted as 37 kB gzipped, and the changelog has an Unreleased entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
While the camera moves, lay the workspace out once for a view covering the whole move and move it with one transform on the layer, instead of laying out every panel each frame. Off by default; toggle in the IDE status bar or palette, or W in the e2e stress scenario. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ut cost Predicts a normal moving frame's cost from timed layouts (calibrated by measured moving frames) and uses the world transform when it would take over 70% of a display frame, returning below 35%. Late frames switch a move mid-way and bias the next few. Moves with under 12 panels never use it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replace the measured per-machine choice with a deterministic rule: a camera
move uses the world transform when at least minPanels panels are in view
where it starts or ends. "auto" is { minPanels: 40 }, from benchmarks
where 36 panels kept up with the CPU slowed 4x and 49 began to stutter.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A move sent somewhere else mid-way is decided again for its new end. Tests wait for the camera to be still across animation frames instead of wall-clock intervals, and record only frames the camera moved in: WebKit in CI draws slowly and may run a frame's callbacks before the workspace's. E2E_PORT picks another port for the test server. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Builds on #1 (Tier 1); merging this also lands #1.
Experimental
worldTransformoptionWhile the camera moves, the workspace is laid out once, for a view covering the whole move, and each frame sets one transform on the layer, instead of laying out every panel on every frame. When the camera stops, everything is laid out normally again.
true/false(default){ minPanels: n }: only for moves with at leastnpanels in view where they start or end, decided when the camera starts moving"auto":{ minPanels: 40 }. With the CPU slowed 4×, laying out 36 panels per frame kept up and 49 began to stutter.With 100 panels and the CPU slowed 4×, slow frames during an animated zoom fall from about 40% to under 10%, and during a pinch from about 25% to about 5%.
Trade-offs while the camera moves, documented in
docs/performance.md: chrome, text and gaps scale like a picture; zooming in looks slightly soft until it stops; collapsed groups and icon tiles are chosen for the laid-out view.Also:
world-transformattribute on the custom elementnpm run benchtakesWORLD=1|auto,SIZES=6x6,8x8andTHROTTLES=4Tests
E2E checks for the world transform:
E2E checks for the threshold:
The custom-element attribute is covered too.
🤖 Generated with Claude Code