Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,29 @@
rendering, so maintainer notes stay out of the user-facing window. No emoji from
1.64 on (owner rule: no emoji in the UI); the app strips them from older entries. -->

## 1.66.0 — Menus and panels, polished

### Sidebars and the dock
- **Handles stay out of the way**: when the bottom dock leaves no room above it, the sidebar handles go behind it and come back when it hides; each handle keeps its place in proportion when the window is resized. <!-- uir-polish A1/A2 -->
- **Docked windows' side panes**: a closed pane's handle sits flush against the window edge, the main area keeps its scrollbar clear of it, and **Ctrl+B** / **Ctrl+Alt+B** open and close the panes of the docked window under the mouse or holding the focus. **Switch sidebar side** moved into the handles' right-click menu. <!-- uir-polish B1-B6 -->
- **Tabs keep their names**: sidebar tabs never shrink; when they do not fit, a **...** button lists them all and the mouse wheel scrolls the strip. A menu row that moves a window reads **Move here**. <!-- uir-polish F1-F3 -->

### Properties and Configure Scene
- **No pin, no lock**: Properties follows your selection and keeps showing the last object after you click away (it closes when that object is deleted); its header always stays at the top. <!-- uir-polish E1-E4 -->
- **Configure Scene moves on its own**: drag its tab to the other sidebar and Properties stays where it is. <!-- uir-polish E5 -->

### Windows
- **Dock and Pop out in every floating header**: one icon-only **Dock** button (and **Pop out** where a window can pop out) in the Node editor, Timeline, Explorer, Objects, Chat, Free assets and the other dockable windows. Docked, a window closes from its dock tab; Code docked has no header row at all. <!-- uir-polish G1-G4 -->

### Main menu and reports
- **Layouts** is the first row of **Window**; **What's new** is the version line at the bottom, with a dot when there is something new. The menu is solid to its bottom edge, and **Help** is a grid with a bug icon on **Report a bug**. <!-- uir-polish C1-C4 -->
- **One Report a bug view**: the moment report and the bug report are one form. It names the seconds it holds ("the last 16 s"), and with no account it sends through the anonymous channel. <!-- uir-polish D1 -->

## 1.65.1 — Safer loading

- **Objects and materials from other people and from files are checked before they load.** Anything that does not pass loads like a missing file, and the rest of the scene is unchanged.


## 1.65.0 — New menus and panels

### Chat and the AI assistant
Expand Down
11 changes: 9 additions & 2 deletions perf/boot-budget.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
"pages": {
"play": {
"html": "play.html",
"maxJsGzBytes": 2097152,
"maxJsGzBytes": 2162688,
"maxFirstFrameMs": 20000
},
"editor": {
"html": "index.html",
"maxJsGzBytes": 3407872,
"maxJsGzBytes": 3538944,
"maxFirstFrameMs": 32000
}
},
Expand All @@ -21,6 +21,13 @@
"editor": "3042.2 KB measured (3133 KB at v1.56.0) -> line 3328 KB, the looser line",
"note": "first lines: the play entry's boot (SP1) and the editor's, gzip -9 initial JS",
"firstFrame": "throttled (slow 4G + 4x CPU, median of 5 on the Deck): play 14641 ms, editor 23647 ms -> loose lines 20000 / 32000 ms (x1.35: a shared runner is noisy; the byte lines are the precise gate)"
},
{
"date": "2026-11-11",
"lane": "uir-polish (1.66.0)",
"play": "1.63.0 1987.1 KB -> 1.64.0 2066.7 (+79.6, over) -> 1.65.0 2073.0 (+6.3) -> 1.65.1 2082.9 (+9.9) -> 1.66 2083.6 (+0.7) -> line 2112 KB",
"editor": "1.63.0 3229.4 KB -> 1.64.0 3383.8 (+154.4, over) -> 1.65.0 3410.0 (+26.2) -> 1.65.1 3421.9 (+11.9) -> 1.66 3424.2 (+2.3) -> line 3456 KB",
"note": "main CI was red on this step from 1.64.0 to 1.65.1 (numbers from each tag's ci.yml run). The line catches up with what shipped and leaves ~30 KB of room; it is NOT a new allowance: the 1.64/1.65 growth (levels, the new menus and panels, safer loading) belongs in lazy chunks, a master-plan card, and the lines come back down when that lands"
}
],
"throttle": {
Expand Down
2 changes: 0 additions & 2 deletions src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
// 26-A: the desktop Statistics window + the sampler that feeds it and the status-line
// budget meter. `renderer.info` had exactly one reader before this (the VR plate).
import StatsOverlay from './components/menu/StatsOverlay.svelte'
import MomentReport from './components/menu/MomentReport.svelte'
import ProblemReport from './components/menu/ProblemReport.svelte' // 37 R20
import { startSceneMetrics, budgetSummary } from './lib/sceneBudget'
import { startPerfRecorder } from './lib/perf/recorder'
Expand Down Expand Up @@ -553,7 +552,6 @@ import { startMusicToolbox } from './lib/musicToolbox'
{/if}
<DungeonMinimap />
<StatsOverlay />
<MomentReport />
<ProblemReport />
<!-- 47-cc0: the Asset Browser — loaded the first time it opens, so the boot carries none of it -->
{#if $assetBrowserOpen}
Expand Down
20 changes: 19 additions & 1 deletion src/components/ContextMenuItems.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
// { section: 'Edit' } a quiet uppercase section label
// icon: 'copy' lucide kebab name (ui/Icon.svelte)
// hint: 'Ctrl+D' dimmed right-aligned shortcut hint
// hoverHint: 'Move here' (uir-polish F3) replaces `hint` while the row is hovered or
// keyboard-highlighted — what a press will DO, where `hint` says where it is
// 16-P3 adds `checked: true` — the ACTIVE choice of a group (bold + accent),
// which replaced the old '● ' label prefix.
//
Expand Down Expand Up @@ -285,7 +287,11 @@
<span class="ctx-ico">{#if rowIcon(item)}<Icon name={rowIcon(item) ?? ""} size={16} />{/if}</span>
{/if}
<span class="flex-1">{item.label}</span>
{#if item.hint}
{#if item.hint && item.hoverHint}
<!-- uir-polish F3: a row that MOVES its window says so while it is hovered / highlighted -->
<span class="ctx-hint ctx-hint-rest">{item.hint}</span>
<span class="ctx-hint ctx-hint-hover" data-ctx-hover-hint>{item.hoverHint}</span>
{:else if item.hint}
<span class="ctx-hint">{item.hint}</span>
{/if}
{#if item.rowActions}
Expand Down Expand Up @@ -437,4 +443,16 @@
font-size: var(--fs-badge);
color: var(--text-faint);
}
.ctx-hint-hover {
display: none;
color: var(--accent-text);
}
.ctx-row:hover .ctx-hint-rest,
.ctx-row.ctx-active .ctx-hint-rest {
display: none;
}
.ctx-row:hover .ctx-hint-hover,
.ctx-row.ctx-active .ctx-hint-hover {
display: inline;
}
</style>
3 changes: 2 additions & 1 deletion src/components/Flow.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import DockTabs from './DockTabs.svelte';
import WindowChrome from './ui/WindowChrome.svelte';
import Icon from './ui/Icon.svelte';
import HeadDockPop from './ui/HeadDockPop.svelte'; // uir-polish G2/G3
import { dragWindow } from '$lib/dragWindow';
import { focusStack } from '$lib/windowFocus';
import { tabbable, resizeGroup, tabGroups } from '$lib/windowTabs';
Expand Down Expand Up @@ -254,7 +255,7 @@
>
{#snippet actions()}
<button id="flow-add-view" data-wc-chrome class="wc-act" title="Add a view (Flow Code, Animation, UV editor, Shader editor)" aria-label="Add a view" onclick={openAddMenu}><Icon name="plus" size={16} /></button>
<button id="flow-dock" data-wc-chrome class="wc-act-text" title="Dock to the bottom" onclick={() => setDocked(true)}><Icon name="panel-bottom" size={16} />Dock</button>
<HeadDockPop key="flow" title="Node editor" ondock={() => setDocked(true)} dockId="flow-dock" />
{/snippet}
</WindowChrome>
<div class="relative min-h-0 flex-1">
Expand Down
3 changes: 2 additions & 1 deletion src/components/Menu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import BudgetChip from './menu/BudgetChip.svelte'; // 46 B1
import Inspector from './menu/Inspector.svelte';
import SidebarStrips from './menu/SidebarStrips.svelte'; // 42 I2/I3
import { inspectorDual } from '$lib/sidebars'; // uir-polish E5
import SidebarHandles from './menu/SidebarHandles.svelte'; // showhide-v8: the viewport sidebar handles
import MenuSidebar from './menu/Sidebar.svelte';
import TouchTools from './menu/TouchTools.svelte';
Expand Down Expand Up @@ -86,7 +87,7 @@
<!-- 46 B1: the budget chip, placed beside the toolbar pill (hidden in Play with the rest of the chrome) -->
<BudgetChip />
<!-- 70 W2: in a pop-out window the Inspector is unmounted here (one panel, one place) -->
{#if !$panelAway.inspector}<Inspector />{/if}
{#if !$panelAway.inspector}<Inspector />{#if $inspectorDual}<Inspector pane="scene" />{/if}{/if}<!-- uir-polish E5: Configure Scene in its own column -->
<SidebarStrips />
<SidebarHandles />
<MenuSettings />
Expand Down
3 changes: 2 additions & 1 deletion src/components/editors/AnimationWindow.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import { openApplyClip } from '$lib/characterUi.js';
import ClipToolsPanel from './ClipToolsPanel.svelte'; // 57 M3/M8
import Icon from '../ui/Icon.svelte';
import HeadDockPop from '../ui/HeadDockPop.svelte'; // uir-polish G2/G3
import PaneHandle from '../ui/PaneHandle.svelte'; // showhide-v8: the one pane-handle pattern
import { readPanelOpen, writePanelOpen } from '$lib/ui/handheldPanels.js';
import { minimalScroll } from '$lib/ui/minimalScroll.js';
Expand Down Expand Up @@ -2848,7 +2849,7 @@
<span class="flex-1"></span>
{/snippet}
{#snippet actions()}
<button data-wc-chrome class="wc-act-text" title="Dock to the bottom" onclick={() => setDocked(true)}><Icon name="panel-bottom" size={16} />Dock</button>
<HeadDockPop key="animation" title="Animation" ondock={() => setDocked(true)} />
{/snippet}
</WindowChrome>
{#if compact && target}<div class="flex w-full shrink-0 items-center gap-2 px-2 py-1">{@render paneSwitch()}</div>{/if}
Expand Down
4 changes: 4 additions & 0 deletions src/components/editors/AssetBrowser.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
// every download lands through $lib/cc0/cc0Import — the Explorer's own import entry for files,
// the environment picker's write for a sky, the material preset library for a material.
import Icon from '../ui/Icon.svelte';
import HeadDockPop from '../ui/HeadDockPop.svelte'; // uir-polish G2
import { dockTab } from '$lib/dockMenu';
import Button from '../ui/Button.svelte';
import Segmented from '../ui/Segmented.svelte';
import Tabs from '../ui/Tabs.svelte';
Expand Down Expand Up @@ -390,8 +392,10 @@
aria-label="Refresh"
onclick={refresh}><Icon name="refresh-cw" size={16} aria-hidden="true" /></button
>
<HeadDockPop key="assets" title="Free assets" ondock={() => dockTab('assets')} btnClass="rounded-sm p-1 hover:brightness-150" />
<button
id="asset-browser-close"
data-wc-x
class="rounded-sm p-1 hover:brightness-150"
title="Close"
aria-label="Close the asset browser"
Expand Down
21 changes: 7 additions & 14 deletions src/components/editors/CodeWorkspace.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import PaneHandle from '../ui/PaneHandle.svelte';
import { paneLocks } from '$lib/ui/paneLocks.js';
import Icon from '../ui/Icon.svelte';
import HeadDockPop from '../ui/HeadDockPop.svelte'; // uir-polish G2/G3
import CodeEditor from './CodeEditor.svelte';
import CodeSidebarLeft from './CodeSidebarLeft.svelte';
import CodeSidebarRight from './CodeSidebarRight.svelte';
Expand Down Expand Up @@ -734,11 +735,6 @@
</div>
{/snippet}

{#snippet popOutButton()}
{#if $popOutSupported}
<button id="code-ws-popout" class="ui-button-quiet" title="Open the code editor in its own browser window (drag it to another monitor)" aria-label="Pop out" onclick={popOut}><Icon name="external-link" size={16} aria-hidden="true" /></button>
{/if}
{/snippet}

{#snippet main()}
<div class="code-main" class:code-narrow={narrow} bind:clientWidth={mainW}>
Expand All @@ -749,7 +745,8 @@
<div class="code-side-grip code-side-grip-l" title="Drag to resize" onpointerdown={(e) => startSide(e, 'left')} onpointermove={moveSide} onpointerup={endSide}></div>
</div>
{/if}
<div class="code-center">
<!-- uir-polish B4: the right handle owns the window's edge — the editor (and its scrollbar) ends where the handle's tab starts -->
<div class="code-center" style:padding-right={narrow ? null : rightShown ? '16px' : '8px'}>
{@render strip()}
{@render body()}
</div>
Expand Down Expand Up @@ -848,11 +845,8 @@
onpointerup={endResize}
></div>
<DockTabs />
<div class="flex shrink-0 items-center gap-1 pb-1">
<span class="tp-dock-title">Code</span>
<span class="flex-1"></span>
{@render popOutButton()}
</div>
<!-- uir-polish G1 (owner 2026-11-11): docked, Code has no header row of its own — the dock tab names it; it
pops out from the tab's menu or by tearing the tab off -->
{@render main()}
</div>
{:else}
Expand All @@ -873,12 +867,11 @@
<WindowChrome
size="tool"
bare
dockedHead="tools"
dockedHead="hide"
body={false}
title="Code"
headerClass="ui-panel-header move-handle cursor-move select-none"
onclose={requestCloseWorkspace}
onpopout={$popOutSupported ? popOut : null}
closeLabel="Close the code workspace"
closeAttrs={{ id: 'code-ws-close', title: 'Close the code workspace' }}
>
Expand All @@ -887,7 +880,7 @@
<span class="flex-1"></span>
{/snippet}
{#snippet actions()}
<button data-wc-chrome class="wc-act-text" title="Dock to the bottom" onclick={() => setDocked(true)}><Icon name="panel-bottom" size={16} />Dock</button>
<HeadDockPop key="code" title="Code" ondock={() => setDocked(true)} onpopout={popOut} popId="code-ws-popout" />
{/snippet}
</WindowChrome>
<div class="flex min-h-0 flex-1 flex-col p-1">{@render main()}</div>
Expand Down
3 changes: 2 additions & 1 deletion src/components/editors/Explorer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { showChoice, showConfirm } from '$lib/confirmDialog.js';
import { safeHtml } from '$lib/sandbox/sanitize.js';
import Icon from '../ui/Icon.svelte';
import HeadDockPop from '../ui/HeadDockPop.svelte'; // uir-polish G2/G3
import EmptyState from '../ui/EmptyState.svelte';
import { FILE_TEMPLATES } from '$lib/codeFilesCore.js';
import { isViewer } from '$lib/objectPermissions';
Expand Down Expand Up @@ -9005,7 +9006,7 @@
</div>
{/snippet}
{#snippet actions()}
<button id="explorer-dock" data-wc-chrome class="wc-act-text" title="Dock to the bottom" onclick={() => setDocked(true)}><Icon name="panel-bottom" size={16} />Dock</button>
<HeadDockPop key="explorer" title="Explorer" ondock={() => setDocked(true)} dockId="explorer-dock" />
{/snippet}
</WindowChrome>
<div class="min-h-0 flex-1 p-1">
Expand Down
2 changes: 1 addition & 1 deletion src/components/editors/FilePreviewWindow.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -856,7 +856,7 @@
onclick={() => openPreviewCog.set(cogOpen ? null : winId)}
><Icon name="settings" size={16} aria-hidden="true" /></button
>
<button id="preview-close" class="ui-button-quiet" title="Close" aria-label="Close" onclick={() => void close()}><Icon name="x" size={16} aria-hidden="true" /></button>
<button id="preview-close" data-wc-x class="ui-button-quiet" title="Close" aria-label="Close" onclick={() => void close()}><Icon name="x" size={16} aria-hidden="true" /></button>
</div>

{#if cogOpen && !editing}
Expand Down
3 changes: 2 additions & 1 deletion src/components/editors/HudEditor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
// and it belongs on this side of the seam.
import { untrack } from 'svelte';
import Icon from '../ui/Icon.svelte';
import HeadDockPop from '../ui/HeadDockPop.svelte'; // uir-polish G2/G3
import { hudEditorClose, showToast } from '../../stores/appStore.js';
import {
hudDocs, hudRuntime, hudSelection, hudScreenOverride, HUD_ANCHORS, HUD_SCENE_KEY,
Expand Down Expand Up @@ -1495,7 +1496,7 @@
<span class="flex-1"></span>
{/snippet}
{#snippet actions()}
<button data-wc-chrome class="wc-act-text" title="Dock to the bottom" onclick={() => setDocked(true)}><Icon name="panel-bottom" size={16} />Dock</button>
<HeadDockPop key="hud" title="HUD editor" ondock={() => setDocked(true)} />
{/snippet}
</WindowChrome>
<div class="flex min-h-0 flex-1 flex-col">
Expand Down
3 changes: 2 additions & 1 deletion src/components/editors/Profiler.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import { onMount, untrack } from 'svelte';
import { get } from 'svelte/store';
import Icon from '../ui/Icon.svelte';
import HeadDockPop from '../ui/HeadDockPop.svelte'; // uir-polish G2/G3
import { profilerLiveOpen } from '$lib/perf/liveSink';
import DockTabs from '../DockTabs.svelte';
import WindowChrome from '../ui/WindowChrome.svelte';
Expand Down Expand Up @@ -1016,7 +1017,7 @@
{#if !myGroup}<ScrollStrip class="pf-strip" label="Profiler tools" id="profiler-toolbar">{@render controls()}</ScrollStrip>{:else}<span class="flex-1"></span>{/if}
{/snippet}
{#snippet actions()}
<button data-wc-chrome class="wc-act-text" title="Dock to the bottom" onclick={() => setDocked(true)}><Icon name="panel-bottom" size={16} />Dock</button>
<HeadDockPop key="profiler" title="Profiler" ondock={() => setDocked(true)} />
{/snippet}
</WindowChrome>
{#if myGroup}
Expand Down
3 changes: 2 additions & 1 deletion src/components/editors/ShaderEditor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import { untrack } from 'svelte';
import { get } from 'svelte/store';
import Icon from '../ui/Icon.svelte';
import HeadDockPop from '../ui/HeadDockPop.svelte'; // uir-polish G2/G3
import { minimalScroll } from '$lib/ui/minimalScroll.js';
import {
SvelteFlow,
Expand Down Expand Up @@ -1128,7 +1129,7 @@
<span class="flex-1"></span>
{/snippet}
{#snippet actions()}
<button data-wc-chrome class="wc-act-text" id="shader-dock" title="Dock to the bottom" aria-label="Dock the shader editor" onclick={() => setDocked(true)}><Icon name="panel-bottom" size={16} />Dock</button>
<HeadDockPop key="shader" title="Shader editor" ondock={() => setDocked(true)} dockId="shader-dock" />
{@render editorActions()}
{/snippet}
</WindowChrome>
Expand Down
8 changes: 2 additions & 6 deletions src/components/editors/TimelineEditor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import { untrack } from 'svelte';
import { get } from 'svelte/store';
import Icon from '../ui/Icon.svelte';
import HeadDockPop from '../ui/HeadDockPop.svelte'; // uir-polish G2/G3
import Button from '../ui/Button.svelte';
import Toggle from '../ui/Toggle.svelte';
import EmptyState from '../ui/EmptyState.svelte';
Expand Down Expand Up @@ -1411,12 +1412,7 @@
<span class="flex-1"></span>
{/snippet}
{#snippet actions()}
<button
data-wc-chrome
class="wc-act-text"
title="Dock to the bottom"
onclick={() => setDocked(true)}><Icon name="panel-bottom" size={16} />Dock</button
>
<HeadDockPop key="timeline" title="Timeline" ondock={() => setDocked(true)} />
{/snippet}
</WindowChrome>
<div class="flex min-h-0 flex-1 flex-col">
Expand Down
3 changes: 2 additions & 1 deletion src/components/editors/UvEditor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// DOWN in canvas space, so every mapping flips Y.
import { onMount, untrack } from 'svelte';
import Icon from '../ui/Icon.svelte';
import HeadDockPop from '../ui/HeadDockPop.svelte'; // uir-polish G2/G3
import ScrollStrip from '../ui/ScrollStrip.svelte';
import { selectedObject, selectedObjects, objectsGroup, globalScene } from '../../stores/sceneStore';
import { uvEditorClose, showToast } from '../../stores/appStore.js';
Expand Down Expand Up @@ -2067,7 +2068,7 @@
<span class="flex-1"></span>
{/snippet}
{#snippet actions()}
<button data-wc-chrome class="wc-act-text" title="Dock to the bottom" onclick={() => setDocked(true)}><Icon name="panel-bottom" size={16} />Dock</button>
<HeadDockPop key="uv" title="UV editor" ondock={() => setDocked(true)} />
{/snippet}
</WindowChrome>
<div class="flex min-h-0 flex-1 flex-col">
Expand Down
3 changes: 3 additions & 0 deletions src/components/menu/Chat.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import WindowChrome from '../ui/WindowChrome.svelte';
import Button from '../ui/Button.svelte';
import Icon from '../ui/Icon.svelte';
import HeadDockPop from '../ui/HeadDockPop.svelte'; // uir-polish G2
import { dockTab } from '$lib/dockMenu';
import ChatSession from './ChatSession.svelte';
import ChatAssistant from './ChatAssistant.svelte';
import ChatHistory from './ChatHistory.svelte';
Expand Down Expand Up @@ -232,6 +234,7 @@
onclick={startNewChat}><Icon name="plus" size={16} /></button
>
{/if}
<HeadDockPop key="chat" title="Chat" ondock={() => dockTab('chat')} />
{/snippet}
</WindowChrome>
<!-- the tabs: a row under the title, so the header stays the window's grip (a press on a tab is
Expand Down
Loading
Loading