pixifact-cli 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ :root{color:#d9dee7;font-synthesis:none;text-rendering:optimizelegibility;--bg:#111318;--panel:#171a20;--panel-raised:#1d2129;--canvas:#0d0f13;--line:#2a2f39;--line-strong:#39404d;--text:#d9dee7;--muted:#818997;--faint:#596171;--focus:#4c8dff;--focus-soft:#213a63;--success:#51b785;--warning:#d4a64f;--danger:#e36f6f;--control:#11141a;background:#111318;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}*{box-sizing:border-box}html,body,#app{width:100%;height:100%;margin:0;overflow:hidden}button,input,select{color:inherit;font:inherit;letter-spacing:0}button{border:0}.editor-shell{background:var(--bg);grid-template-rows:42px 34px minmax(0,1fr);width:100%;height:100%;display:grid}.editor-session-standby{background:var(--bg);place-items:center;width:100%;height:100%;display:grid}.editor-session-standby>section{gap:18px;width:min(420px,100vw - 40px);display:grid}.standby-product{color:var(--faint);font-size:10px;font-weight:750}.editor-session-standby h1{color:var(--text);letter-spacing:0;margin:0;font-size:18px}.standby-context{border-top:1px solid var(--line);border-bottom:1px solid var(--line);grid-template-columns:76px minmax(0,1fr);gap:8px 12px;padding:14px 0;display:grid}.standby-context span{color:var(--muted);font-size:12px}.standby-context strong{min-width:0;color:var(--text);text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:500;overflow:hidden}.takeover-button{background:var(--focus);color:#fff;cursor:pointer;border:1px solid #659cff;border-radius:4px;justify-self:start;min-width:104px;height:32px;padding:0 14px;font-size:12px;font-weight:650}.takeover-button:hover:not(:disabled){background:#5a96ff}.standby-note,.standby-error{margin:-6px 0 0;font-size:11px;line-height:1.6}.standby-note{color:var(--muted)}.standby-error{color:var(--danger)}.topbar{border-bottom:1px solid var(--line);background:#14171c;grid-template-columns:232px minmax(0,1fr) auto 112px;align-items:center;min-width:0;display:grid}.brand{border-right:1px solid var(--line);color:#f1f4f8;align-items:center;height:100%;padding:0 14px;font-size:11px;font-weight:750;display:flex}.scene-identity{align-items:baseline;gap:10px;min-width:0;padding:0 14px;display:flex}.scene-identity strong{flex:none;font-size:13px}.scene-identity span{min-width:0;color:var(--muted);text-overflow:ellipsis;white-space:nowrap;font-size:11px;overflow:hidden}.history-tools{align-items:center;gap:2px;padding-right:10px;display:flex}.history-tools button,.reset-button{width:28px;height:28px;color:var(--muted);cursor:pointer;background:0 0;border-radius:4px;place-items:center;padding:0;display:inline-grid}.history-tools button:hover:not(:disabled),.reset-button:hover:not(:disabled){background:var(--panel-raised);color:var(--text)}.history-tools .save-button{width:auto;color:var(--text);gap:5px;padding:0 8px;font-size:11px;display:inline-flex}button:disabled{opacity:.35;cursor:default}.sync-state{border-left:1px solid var(--line);height:100%;color:var(--muted);align-items:center;gap:7px;padding:0 13px;font-size:11px;display:flex}.sync-state span{background:var(--success);border-radius:50%;width:7px;height:7px}.sync-state[data-state=saving] span,.sync-state[data-state=unsaved] span{background:var(--warning)}.sync-state[data-state=conflict] span,.sync-state[data-state=error] span{background:var(--danger)}.scene-tabs{border-bottom:1px solid var(--line);background:#14171c;min-width:0;display:flex;overflow-x:auto}.scene-tab{border-right:1px solid var(--line);max-width:220px;color:var(--muted);flex:none;align-items:center;display:flex}.scene-tab.active{border-bottom:2px solid var(--focus);background:var(--panel);color:var(--text)}.scene-tab-activate{min-width:0;height:31px;color:inherit;cursor:pointer;background:0 0;align-items:center;gap:7px;padding:0 4px 0 12px;font-size:11px;display:flex}.scene-tab-activate>span:first-child{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.scene-tab-status{color:var(--warning);font-size:10px}.scene-tab-status.error{color:var(--danger);font-weight:800}.scene-tab-close{height:25px;color:inherit;cursor:pointer;background:0 0;border-radius:4px;flex:0 0 25px;place-items:center;margin-right:4px;display:grid}.scene-tab-close:hover:not(:disabled){background:var(--line-strong)}.editor-modal-backdrop{z-index:30;background:#07090bcc;place-items:center;display:grid;position:fixed;inset:0}.editor-modal{border:1px solid var(--line-strong);background:var(--panel);width:min(440px,100vw - 32px);color:var(--text);border-radius:6px;padding:20px}.editor-modal h2{margin:0 0 10px;font-size:15px}.editor-modal p{color:var(--muted);margin:0 0 20px;font-size:12px;line-height:1.5}.editor-modal-actions{justify-content:flex-end;gap:8px;display:flex}.editor-modal-actions button{border:1px solid var(--line-strong);background:var(--panel-raised);color:var(--text);cursor:pointer;border-radius:4px;padding:7px 10px;font-size:11px}.editor-modal-actions button.primary{border-color:var(--focus);background:var(--focus);color:#fff}.conflict-modal{width:min(920px,100vw - 32px)}.conflict-sources{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-bottom:20px;display:grid}.conflict-sources strong{margin-bottom:7px;font-size:11px;display:block}.conflict-sources pre{border:1px solid var(--line);background:var(--control);height:min(42vh,340px);color:var(--text);margin:0;padding:10px;font-size:11px;overflow:auto}.workspace{grid-template-columns:minmax(190px,232px) minmax(360px,1fr) minmax(270px,296px);min-width:0;min-height:0;display:grid}.left-panel,.right-panel,.canvas-panel{min-width:0;min-height:0}.left-panel,.right-panel{background:var(--panel)}.left-panel{border-right:1px solid var(--line);flex-direction:column;display:flex}.right-panel{border-left:1px solid var(--line);overflow:auto}.left-tabs{flex:1;grid-template-rows:34px minmax(0,1fr);min-height:0;display:grid}.left-panel-footer{border-top:1px solid var(--line);flex:0 0 44px;align-items:center;padding:0 8px;display:flex}.settings-trigger{width:100%;height:32px;color:var(--muted);text-align:left;cursor:pointer;background:0 0;border-radius:4px;align-items:center;gap:9px;padding:0 8px;font-size:12px;display:flex}.settings-trigger:hover,.settings-trigger[data-state=open]{background:var(--panel-raised);color:var(--text)}.editor-settings-popover{z-index:20;border:1px solid var(--line-strong);background:var(--panel-raised);width:248px;color:var(--text);border-radius:7px;padding:12px;box-shadow:0 10px 30px #0007}.settings-heading{border-bottom:1px solid var(--line-strong);padding:0 2px 10px;font-size:12px;font-weight:700}.settings-option{cursor:pointer;justify-content:space-between;align-items:center;gap:14px;padding:12px 2px 2px;display:flex}.settings-option span{gap:4px;display:grid}.settings-option strong{font-size:12px;font-weight:600}.settings-option small{color:var(--muted);font-size:11px}.settings-option input{accent-color:var(--focus);cursor:pointer}.tab-list{border-bottom:1px solid var(--line);grid-template-columns:1fr 1fr;display:grid}.tab-trigger{color:var(--muted);cursor:pointer;background:0 0;font-size:11px;position:relative}.tab-trigger[data-state=active]{color:var(--text)}.tab-trigger[data-state=active]:after{background:var(--focus);content:"";height:2px;position:absolute;bottom:-1px;left:12px;right:12px}.tab-content{outline:none;min-height:0;overflow:auto}.panel-title,.inspector-section-title,.asset-group-label{color:var(--muted);font-size:10px;font-weight:700}.panel-title{border-bottom:1px solid var(--line);align-items:center;height:34px;padding:0 12px;display:flex}.tree-list{margin:0;padding:0;list-style:none}.hierarchy-panel{min-height:100%;padding:0 0 6px}.hierarchy-toolbar{z-index:2;border-bottom:1px solid var(--line);background:var(--panel);grid-template-columns:minmax(0,1fr) 27px 27px 27px;align-items:center;gap:2px;height:35px;padding:4px 6px;display:grid;position:sticky;top:0}.hierarchy-toolbar select{border:1px solid var(--line-strong);background:var(--control);width:100%;min-width:0;height:25px;color:var(--text);border-radius:3px;outline:none;padding:0 5px;font-size:10px}.hierarchy-toolbar select:focus{border-color:var(--focus)}.hierarchy-toolbar button{width:27px;height:27px;color:var(--muted);cursor:pointer;background:0 0;border-radius:3px;place-items:center;padding:0;display:grid}.hierarchy-toolbar button:hover:not(:disabled){background:var(--panel-raised);color:var(--text)}.tree-row{width:100%;height:27px;color:var(--text);text-align:left;cursor:default;background:0 0;grid-template-columns:15px 16px minmax(0,1fr) auto;align-items:center;gap:4px;padding-top:0;padding-bottom:0;padding-right:9px;display:grid;position:relative}.hierarchy-panel.is-dragging .tree-row{cursor:grabbing}.hierarchy-panel.is-asset-dragging .tree-row{cursor:copy}.tree-row.drop-inside{box-shadow:inset 0 0 0 1px var(--focus);background:#26364d}.tree-row.drop-before:before,.tree-row.drop-after:after{z-index:1;background:var(--focus);content:"";pointer-events:none;height:2px;position:absolute;left:5px;right:5px}.tree-row.drop-before:before{top:-1px}.tree-row.drop-after:after{bottom:-1px}.tree-row:hover{background:#20242c}.tree-row.selected{background:var(--focus-soft);color:#eef5ff}.tree-disclosure{width:15px;height:20px;color:var(--muted);place-items:center;display:grid}.tree-disclosure.empty{visibility:hidden}.tree-icon{color:#8da4c7}.tree-label{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:12px;overflow:hidden}.tree-row small{color:var(--faint);font-size:9px}.scene-root{cursor:default;padding-left:8px;font-weight:650}.scene-mark{color:#a9c8f8;border:1px solid #637a9d;border-radius:3px;place-items:center;width:14px;height:14px;font-size:8px;display:grid}.asset-list{padding:7px 0 14px}.asset-row{width:100%;height:29px;color:var(--text);text-align:left;background:0 0;grid-template-columns:14px 18px minmax(0,1fr);align-items:center;gap:5px;padding:0 12px;display:grid}button.asset-row{cursor:pointer}.asset-directory{color:var(--muted)}.asset-directory svg:nth-of-type(2){color:#a9c8f8}.asset-row[data-asset-draggable=true]{cursor:grab;-webkit-user-select:none;user-select:none}.asset-row:hover,.asset-row.selected{background:#20242c}.asset-row.selected{color:#a9ccff}.asset-row.focused{box-shadow:inset 2px 0 var(--focus);background:#2a3a52}.asset-row span{text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.asset-row .asset-row-spacer{width:14px}.asset-thumbnail{object-fit:contain;pointer-events:none;border-radius:2px;width:18px;height:18px}.asset-row.asset-draggable{color:var(--muted)}.asset-empty,.panel-empty{color:var(--faint);padding:14px 12px;font-size:12px}.panel-empty.compact{padding-top:18px}.canvas-panel{background:var(--canvas);position:relative}.scene-canvas-host{-webkit-user-select:none;user-select:none;position:absolute;inset:0;overflow:hidden}.scene-canvas-host.is-asset-drop-target:after{z-index:2;border:1px solid var(--focus);content:"";pointer-events:none;position:absolute;inset:3px}.canvas-grid{pointer-events:none;background-image:linear-gradient(#20242b 1px,#0000 1px),linear-gradient(90deg,#20242b 1px,#0000 1px);background-size:24px 24px;position:absolute;inset:0}.scene-canvas{display:block;position:absolute;inset:0}.scene-canvas-host.is-pan-ready .scene-canvas{cursor:grab!important}.scene-canvas-host.is-panning .scene-canvas{cursor:grabbing!important}.canvas-tools{z-index:3;position:absolute;top:10px;right:10px}.canvas-mode-tools{gap:4px;display:flex;left:10px;right:auto}.canvas-tools button{border:1px solid var(--line);background:var(--panel);width:28px;height:28px;color:var(--muted);cursor:pointer;border-radius:4px;place-items:center;padding:0;display:inline-grid}.canvas-tools button:hover:not(:disabled){border-color:var(--line-strong);background:var(--panel-raised);color:var(--text)}.canvas-tools button[aria-pressed=true]{border-color:var(--focus);background:var(--focus-soft);color:var(--text)}.canvas-status{border:1px solid var(--line);max-width:min(520px,100% - 48px);color:var(--muted);background:#15181e;border-radius:4px;padding:7px 10px;font-size:12px;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.inspector-panel{min-height:0}.inspector-heading{border-bottom:1px solid var(--line);justify-content:space-between;align-items:center;min-height:54px;padding:8px 12px;display:flex}.inspector-heading div{gap:3px;min-width:0;display:grid}.inspector-heading strong{text-overflow:ellipsis;white-space:nowrap;font-size:13px;overflow:hidden}.inspector-heading small{color:var(--muted);font-size:10px}.inspector-section-title{border-bottom:1px solid var(--line);height:28px;padding:9px 12px 0}.property-row{border-bottom:1px solid #21252d;grid-template-columns:minmax(0,1fr);min-height:34px;padding:3px 8px 3px 12px;display:grid}.property-row.is-paired{grid-template-columns:repeat(2,minmax(0,1fr));gap:6px}.property-field{grid-template-columns:minmax(70px,.8fr) minmax(120px,1.4fr);align-items:center;min-width:0;display:grid}.property-row.is-paired .property-field{grid-template-columns:max-content minmax(0,1fr);align-items:center;gap:4px}.property-row.is-paired .property-field>span{font-size:10px}.property-row.is-paired .property-control{grid-template-columns:minmax(0,1fr) 20px;gap:2px}.property-row.is-paired .reset-button{width:20px}.property-field>span{color:var(--text);text-overflow:ellipsis;white-space:nowrap;font-size:11px;overflow:hidden}.property-field>span.inherited{color:var(--muted)}.property-field.is-image-drop-candidate{box-shadow:inset 2px 0 var(--success);cursor:copy;background:#162b24}.property-field.is-image-drop-candidate:hover{background:#1b372d}.property-field.is-image-drop-candidate .property-control input[type=text]{border-color:var(--success)}.property-control{grid-template-columns:minmax(0,1fr) 24px;align-items:start;gap:3px;display:grid}.node-id-control{grid-template-columns:minmax(0,1fr)}.property-value{gap:3px;min-width:0;display:grid}.property-control input[type=text],.property-control input[type=number],.property-control select{border:1px solid var(--line-strong);background:var(--control);width:100%;min-width:0;height:25px;color:var(--text);border-radius:3px;outline:none;padding:0 7px;font-size:11px}.property-control input.resource-reference{cursor:alias}.property-control input:focus,.property-control select:focus{border-color:var(--focus)}.property-control input[type=text].is-invalid,.property-control input[type=text].is-invalid:focus{border-color:var(--danger)}.property-control input:disabled,.property-control select:disabled{color:#9ca6b5;cursor:default;opacity:1;background:#1b1f26;border-color:#303640}.property-control input[type=checkbox]{width:15px;height:15px;accent-color:var(--focus)}.property-control input[type=color]{border:1px solid var(--line-strong);background:var(--control);border-radius:3px;width:34px;height:24px;padding:2px}.reset-button{width:24px;height:24px}.binding-source{color:#8eb8e8;text-overflow:ellipsis;white-space:nowrap;align-items:center;gap:4px;min-width:0;font-size:10px;display:flex;overflow:hidden}.inline-error,.global-error{color:#ffd1d1;margin:0;font-size:11px}.inline-error{background:#2d1b20;border-bottom:1px solid #4f292f;padding:9px 12px}.global-error{background:#321e23;border:1px solid #66343c;border-radius:4px;max-width:min(520px,100vw - 24px);padding:9px 11px;position:fixed;bottom:12px;right:12px}@media (width<=860px){.workspace{grid-template-columns:190px minmax(320px,1fr) 270px}.topbar{grid-template-columns:190px minmax(0,1fr) auto 100px}}
@@ -1 +1 @@
1
- import{E as e,_ as t,g as n,v as r}from"./captureCompilerScenePreview-CeYQNPPP.js";e.add(n,r),e.add(t);
1
+ import{E as e,_ as t,g as n,v as r}from"./captureCompilerScenePreview-CksQqv9T.js";e.add(n,r),e.add(t);
@@ -0,0 +1 @@
1
+ import"./captureCompilerScenePreview-CksQqv9T.js";import"./init-Cun-jBBV.js";
@@ -3,8 +3,8 @@
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <title>Pixifact Scene Capture</title>
6
- <script type="module" crossorigin src="/assets/capture-DkKec9UG.js"></script>
7
- <link rel="modulepreload" crossorigin href="/assets/captureCompilerScenePreview-CeYQNPPP.js">
6
+ <script type="module" crossorigin src="/assets/capture--KpnplUn.js"></script>
7
+ <link rel="modulepreload" crossorigin href="/assets/captureCompilerScenePreview-CksQqv9T.js">
8
8
  </head>
9
9
  <body>
10
10
  </body>
package/editor/index.html CHANGED
@@ -4,9 +4,9 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Pixifact Editor</title>
7
- <script type="module" crossorigin src="/assets/editor-CCOqWQMU.js"></script>
8
- <link rel="modulepreload" crossorigin href="/assets/captureCompilerScenePreview-CeYQNPPP.js">
9
- <link rel="stylesheet" crossorigin href="/assets/editor-B_YR_yGH.css">
7
+ <script type="module" crossorigin src="/assets/editor-CdMzlphb.js"></script>
8
+ <link rel="modulepreload" crossorigin href="/assets/captureCompilerScenePreview-CksQqv9T.js">
9
+ <link rel="stylesheet" crossorigin href="/assets/editor-rwswALuA.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="app"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pixifact-cli",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "Pixifact Scene 自动化 CLI。",
5
5
  "packageManager": "bun@1.3.13",
6
6
  "type": "module",
@@ -32,7 +32,7 @@
32
32
  "start": "bun src/pixifact-cli.ts"
33
33
  },
34
34
  "dependencies": {
35
- "pixifact": "^0.12.0",
35
+ "pixifact": "^0.13.0",
36
36
  "playwright": "1.58.2",
37
37
  "vite": "^8.0.10"
38
38
  }
@@ -38,6 +38,9 @@ interface EditorProjectFile {
38
38
 
39
39
  interface EditorUiState {
40
40
  assetTreeExpandedDirectories?: string[];
41
+ autoSave: boolean;
42
+ openScenePaths?: string[];
43
+ activeScenePath?: string;
41
44
  }
42
45
 
43
46
  interface BunServer {
@@ -176,16 +179,32 @@ function parseEditorUiState(value: unknown): EditorUiState {
176
179
  throw new Error('Editor UI state must be a JSON object.');
177
180
  }
178
181
  const directories = (value as Record<string, unknown>).assetTreeExpandedDirectories;
179
- if (directories === undefined) return {};
180
- if (!Array.isArray(directories) || directories.some((directory) => typeof directory !== 'string')) {
182
+ const autoSave = (value as Record<string, unknown>).autoSave;
183
+ const openScenePaths = (value as Record<string, unknown>).openScenePaths;
184
+ const activeScenePath = (value as Record<string, unknown>).activeScenePath;
185
+ if (directories !== undefined && (!Array.isArray(directories) || directories.some((directory) => typeof directory !== 'string'))) {
181
186
  throw new Error('Editor UI state assetTreeExpandedDirectories must be a string array.');
182
187
  }
183
- return { assetTreeExpandedDirectories: directories };
188
+ if (autoSave !== undefined && typeof autoSave !== 'boolean') {
189
+ throw new Error('Editor UI state autoSave must be a boolean.');
190
+ }
191
+ if (openScenePaths !== undefined && (!Array.isArray(openScenePaths) || openScenePaths.some((scenePath) => typeof scenePath !== 'string'))) {
192
+ throw new Error('Editor UI state openScenePaths must be a string array.');
193
+ }
194
+ if (activeScenePath !== undefined && typeof activeScenePath !== 'string') {
195
+ throw new Error('Editor UI state activeScenePath must be a string.');
196
+ }
197
+ return {
198
+ ...(directories === undefined ? {} : { assetTreeExpandedDirectories: directories }),
199
+ autoSave: autoSave ?? false,
200
+ ...(openScenePaths === undefined ? {} : { openScenePaths }),
201
+ ...(activeScenePath === undefined ? {} : { activeScenePath }),
202
+ };
184
203
  }
185
204
 
186
205
  function readEditorUiState(projectRoot: string): EditorUiState {
187
206
  const statePath = editorUiStatePath(projectRoot);
188
- if (!fs.existsSync(statePath)) return {};
207
+ if (!fs.existsSync(statePath)) return { autoSave: false };
189
208
  return parseEditorUiState(JSON.parse(fs.readFileSync(statePath, 'utf8')));
190
209
  }
191
210
 
@@ -244,8 +263,8 @@ export function createEditorProjectService(options: EditorProjectServiceOptions)
244
263
  if (url.pathname === '/api/editor-ui-state' && request.method === 'PUT') {
245
264
  const body = await readJsonBody(request);
246
265
  const state = parseEditorUiState(body);
247
- if (!state.assetTreeExpandedDirectories) {
248
- throw new EditorRequestError(400, 'Editor UI state requires assetTreeExpandedDirectories.');
266
+ if (!state.assetTreeExpandedDirectories || typeof body.autoSave !== 'boolean') {
267
+ throw new EditorRequestError(400, 'Editor UI state requires assetTreeExpandedDirectories and autoSave.');
249
268
  }
250
269
  return jsonResponse(writeEditorUiState(projectRoot, state));
251
270
  }
@@ -4,9 +4,9 @@ import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import { parseSceneTemplate } from 'pixifact/compiler';
6
6
 
7
- export const editorSessionProtocolVersion = 3;
7
+ export const editorSessionProtocolVersion = 4;
8
8
 
9
- export type EditorContextSyncState = 'synced' | 'saving' | 'conflict' | 'error';
9
+ export type EditorContextSyncState = 'synced' | 'unsaved' | 'saving' | 'conflict' | 'error';
10
10
  export type EditorPreviewState = 'loading' | 'ready' | 'error';
11
11
 
12
12
  export type EditorNodeContext =
@@ -47,6 +47,7 @@ export interface EditorBrowserContext {
47
47
  syncState: EditorContextSyncState;
48
48
  };
49
49
  selection: EditorSelectionContext;
50
+ openScenes: Array<{ path: string; syncState: EditorContextSyncState }>;
50
51
  }
51
52
 
52
53
  export interface EditorSessionResumeState {
@@ -152,18 +153,23 @@ function isRecord(value: unknown): value is Record<string, unknown> {
152
153
  }
153
154
 
154
155
  function isEditorBrowserContext(value: unknown): value is EditorBrowserContext {
155
- if (!isRecord(value) || !isRecord(value.scene) || !isRecord(value.selection)) {
156
+ if (!isRecord(value) || !isRecord(value.scene) || !isRecord(value.selection) || !Array.isArray(value.openScenes)) {
156
157
  return false;
157
158
  }
158
159
  const syncState = value.scene.syncState;
159
160
  if (
160
161
  typeof value.scene.path !== 'string'
161
162
  || typeof value.scene.revision !== 'string'
162
- || !['synced', 'saving', 'conflict', 'error'].includes(String(syncState))
163
+ || !['synced', 'unsaved', 'saving', 'conflict', 'error'].includes(String(syncState))
163
164
  || !['loading', 'ready', 'error'].includes(String(value.scene.previewState))
164
165
  ) {
165
166
  return false;
166
167
  }
168
+ if (value.openScenes.some((openScene) => !isRecord(openScene)
169
+ || typeof openScene.path !== 'string'
170
+ || !['synced', 'unsaved', 'saving', 'conflict', 'error'].includes(String(openScene.syncState)))) {
171
+ return false;
172
+ }
167
173
  if (value.selection.kind === 'scene') {
168
174
  return true;
169
175
  }
@@ -179,6 +185,7 @@ export function createEditorHostSession(options: EditorHostSessionOptions) {
179
185
  const browsers = new Set<EditorBrowserSocket>();
180
186
  const pendingScreenshots = new Map<string, PendingEditorScreenshot>();
181
187
  let activeBrowser: EditorBrowserSocket | undefined;
188
+ let activeHasNoScene = false;
182
189
  let context: EditorContext | undefined;
183
190
  let resume: EditorSessionResumeState | undefined;
184
191
  let screenshotSequence = 0;
@@ -225,6 +232,7 @@ export function createEditorHostSession(options: EditorHostSessionOptions) {
225
232
  return false;
226
233
  }
227
234
  activeBrowser = socket;
235
+ activeHasNoScene = false;
228
236
  sendState(socket, 'editorSessionActive');
229
237
  return true;
230
238
  }
@@ -234,6 +242,7 @@ export function createEditorHostSession(options: EditorHostSessionOptions) {
234
242
  if (socket === activeBrowser) {
235
243
  rejectBrowserScreenshots(socket, 'Active Editor browser disconnected during screenshot capture.');
236
244
  activeBrowser = undefined;
245
+ activeHasNoScene = false;
237
246
  context = undefined;
238
247
  }
239
248
  }
@@ -245,7 +254,8 @@ export function createEditorHostSession(options: EditorHostSessionOptions) {
245
254
  }
246
255
  if (parsed.type === 'editorSessionTakeoverRequested') {
247
256
  if (!browsers.has(socket) || socket === activeBrowser) return;
248
- if (activeBrowser && context?.scene.syncState !== 'synced') {
257
+ if (activeBrowser && !activeHasNoScene && (context?.scene.syncState !== 'synced'
258
+ || context.openScenes.some((openScene) => openScene.syncState !== 'synced'))) {
249
259
  sendState(socket, 'editorSessionStandby', {
250
260
  error: '当前 Editor 尚未同步,暂时无法接管。',
251
261
  });
@@ -256,6 +266,7 @@ export function createEditorHostSession(options: EditorHostSessionOptions) {
256
266
  rejectBrowserScreenshots(previous, 'Active Editor browser changed during screenshot capture.');
257
267
  }
258
268
  activeBrowser = socket;
269
+ activeHasNoScene = false;
259
270
  context = undefined;
260
271
  for (const browser of browsers) {
261
272
  if (browser === socket) {
@@ -319,7 +330,15 @@ export function createEditorHostSession(options: EditorHostSessionOptions) {
319
330
  }));
320
331
  return;
321
332
  }
322
- if (socket !== activeBrowser || parsed.type !== 'editorContextChanged') return;
333
+ if (socket !== activeBrowser) return;
334
+ if (parsed.type === 'editorContextCleared') {
335
+ context = undefined;
336
+ resume = undefined;
337
+ activeHasNoScene = true;
338
+ notifyStandbyBrowsers();
339
+ return;
340
+ }
341
+ if (parsed.type !== 'editorContextChanged') return;
323
342
  if (!isEditorBrowserContext(parsed.context)) {
324
343
  throw new Error('Editor context message is invalid.');
325
344
  }
@@ -332,6 +351,7 @@ export function createEditorHostSession(options: EditorHostSessionOptions) {
332
351
  },
333
352
  ...structuredClone(parsed.context),
334
353
  };
354
+ activeHasNoScene = false;
335
355
  resume = {
336
356
  scenePath: context.scene.path,
337
357
  ...(context.selection.kind === 'node'
@@ -1 +0,0 @@
1
- import{C as e,E as t,T as n,b as r,w as i,x as a,y as o}from"./captureCompilerScenePreview-CeYQNPPP.js";import"./init-BTbgjve4.js";t.add(i),t.mixin(n,e),t.add(a),t.add(r),t.mixin(n,o);
@@ -1 +0,0 @@
1
- :root{color:#d9dee7;font-synthesis:none;text-rendering:optimizelegibility;--bg:#111318;--panel:#171a20;--panel-raised:#1d2129;--canvas:#0d0f13;--line:#2a2f39;--line-strong:#39404d;--text:#d9dee7;--muted:#818997;--faint:#596171;--focus:#4c8dff;--focus-soft:#213a63;--success:#51b785;--warning:#d4a64f;--danger:#e36f6f;--control:#11141a;background:#111318;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}*{box-sizing:border-box}html,body,#app{width:100%;height:100%;margin:0;overflow:hidden}button,input,select{color:inherit;font:inherit;letter-spacing:0}button{border:0}.editor-shell{background:var(--bg);grid-template-rows:42px minmax(0,1fr);width:100%;height:100%;display:grid}.editor-session-standby{background:var(--bg);place-items:center;width:100%;height:100%;display:grid}.editor-session-standby>section{gap:18px;width:min(420px,100vw - 40px);display:grid}.standby-product{color:var(--faint);font-size:10px;font-weight:750}.editor-session-standby h1{color:var(--text);letter-spacing:0;margin:0;font-size:18px}.standby-context{border-top:1px solid var(--line);border-bottom:1px solid var(--line);grid-template-columns:76px minmax(0,1fr);gap:8px 12px;padding:14px 0;display:grid}.standby-context span{color:var(--muted);font-size:12px}.standby-context strong{min-width:0;color:var(--text);text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:500;overflow:hidden}.takeover-button{background:var(--focus);color:#fff;cursor:pointer;border:1px solid #659cff;border-radius:4px;justify-self:start;min-width:104px;height:32px;padding:0 14px;font-size:12px;font-weight:650}.takeover-button:hover:not(:disabled){background:#5a96ff}.standby-note,.standby-error{margin:-6px 0 0;font-size:11px;line-height:1.6}.standby-note{color:var(--muted)}.standby-error{color:var(--danger)}.topbar{border-bottom:1px solid var(--line);background:#14171c;grid-template-columns:232px minmax(0,1fr) auto 112px;align-items:center;min-width:0;display:grid}.brand{border-right:1px solid var(--line);color:#f1f4f8;align-items:center;height:100%;padding:0 14px;font-size:11px;font-weight:750;display:flex}.scene-identity{align-items:baseline;gap:10px;min-width:0;padding:0 14px;display:flex}.scene-identity strong{flex:none;font-size:13px}.scene-identity span{min-width:0;color:var(--muted);text-overflow:ellipsis;white-space:nowrap;font-size:11px;overflow:hidden}.history-tools{align-items:center;gap:2px;padding-right:10px;display:flex}.history-tools button,.reset-button{width:28px;height:28px;color:var(--muted);cursor:pointer;background:0 0;border-radius:4px;place-items:center;padding:0;display:inline-grid}.history-tools button:hover:not(:disabled),.reset-button:hover:not(:disabled){background:var(--panel-raised);color:var(--text)}button:disabled{opacity:.35;cursor:default}.sync-state{border-left:1px solid var(--line);height:100%;color:var(--muted);align-items:center;gap:7px;padding:0 13px;font-size:11px;display:flex}.sync-state span{background:var(--success);border-radius:50%;width:7px;height:7px}.sync-state[data-state=saving] span{background:var(--warning)}.sync-state[data-state=conflict] span,.sync-state[data-state=error] span{background:var(--danger)}.workspace{grid-template-columns:minmax(190px,232px) minmax(360px,1fr) minmax(270px,296px);min-width:0;min-height:0;display:grid}.left-panel,.right-panel,.canvas-panel{min-width:0;min-height:0}.left-panel,.right-panel{background:var(--panel)}.left-panel{border-right:1px solid var(--line)}.right-panel{border-left:1px solid var(--line);overflow:auto}.left-tabs{grid-template-rows:34px minmax(0,1fr);height:100%;display:grid}.tab-list{border-bottom:1px solid var(--line);grid-template-columns:1fr 1fr;display:grid}.tab-trigger{color:var(--muted);cursor:pointer;background:0 0;font-size:11px;position:relative}.tab-trigger[data-state=active]{color:var(--text)}.tab-trigger[data-state=active]:after{background:var(--focus);content:"";height:2px;position:absolute;bottom:-1px;left:12px;right:12px}.tab-content{outline:none;min-height:0;overflow:auto}.panel-title,.inspector-section-title,.asset-group-label{color:var(--muted);font-size:10px;font-weight:700}.panel-title{border-bottom:1px solid var(--line);align-items:center;height:34px;padding:0 12px;display:flex}.tree-list{margin:0;padding:0;list-style:none}.hierarchy-panel{min-height:100%;padding:0 0 6px}.hierarchy-toolbar{z-index:2;border-bottom:1px solid var(--line);background:var(--panel);grid-template-columns:minmax(0,1fr) 27px 27px 27px;align-items:center;gap:2px;height:35px;padding:4px 6px;display:grid;position:sticky;top:0}.hierarchy-toolbar select{border:1px solid var(--line-strong);background:var(--control);width:100%;min-width:0;height:25px;color:var(--text);border-radius:3px;outline:none;padding:0 5px;font-size:10px}.hierarchy-toolbar select:focus{border-color:var(--focus)}.hierarchy-toolbar button{width:27px;height:27px;color:var(--muted);cursor:pointer;background:0 0;border-radius:3px;place-items:center;padding:0;display:grid}.hierarchy-toolbar button:hover:not(:disabled){background:var(--panel-raised);color:var(--text)}.tree-row{width:100%;height:27px;color:var(--text);text-align:left;cursor:default;background:0 0;grid-template-columns:15px 16px minmax(0,1fr) auto;align-items:center;gap:4px;padding-top:0;padding-bottom:0;padding-right:9px;display:grid;position:relative}.hierarchy-panel.is-dragging .tree-row{cursor:grabbing}.hierarchy-panel.is-asset-dragging .tree-row{cursor:copy}.tree-row.drop-inside{box-shadow:inset 0 0 0 1px var(--focus);background:#26364d}.tree-row.drop-before:before,.tree-row.drop-after:after{z-index:1;background:var(--focus);content:"";pointer-events:none;height:2px;position:absolute;left:5px;right:5px}.tree-row.drop-before:before{top:-1px}.tree-row.drop-after:after{bottom:-1px}.tree-row:hover{background:#20242c}.tree-row.selected{background:var(--focus-soft);color:#eef5ff}.tree-disclosure{width:15px;height:20px;color:var(--muted);place-items:center;display:grid}.tree-disclosure.empty{visibility:hidden}.tree-icon{color:#8da4c7}.tree-label{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:12px;overflow:hidden}.tree-row small{color:var(--faint);font-size:9px}.scene-root{cursor:default;padding-left:8px;font-weight:650}.scene-mark{color:#a9c8f8;border:1px solid #637a9d;border-radius:3px;place-items:center;width:14px;height:14px;font-size:8px;display:grid}.asset-list{padding:7px 0 14px}.asset-row{width:100%;height:29px;color:var(--text);text-align:left;background:0 0;grid-template-columns:14px 18px minmax(0,1fr);align-items:center;gap:5px;padding:0 12px;display:grid}button.asset-row{cursor:pointer}.asset-directory{color:var(--muted)}.asset-directory svg:nth-of-type(2){color:#a9c8f8}.asset-row[data-asset-draggable=true]{cursor:grab;-webkit-user-select:none;user-select:none}.asset-row:hover,.asset-row.selected{background:#20242c}.asset-row.selected{color:#a9ccff}.asset-row.focused{box-shadow:inset 2px 0 var(--focus);background:#2a3a52}.asset-row span{text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.asset-row .asset-row-spacer{width:14px}.asset-thumbnail{object-fit:contain;pointer-events:none;border-radius:2px;width:18px;height:18px}.asset-row.asset-draggable{color:var(--muted)}.asset-empty,.panel-empty{color:var(--faint);padding:14px 12px;font-size:12px}.panel-empty.compact{padding-top:18px}.canvas-panel{background:var(--canvas);position:relative}.scene-canvas-host{-webkit-user-select:none;user-select:none;position:absolute;inset:0;overflow:hidden}.scene-canvas-host.is-asset-drop-target:after{z-index:2;border:1px solid var(--focus);content:"";pointer-events:none;position:absolute;inset:3px}.canvas-grid{pointer-events:none;background-image:linear-gradient(#20242b 1px,#0000 1px),linear-gradient(90deg,#20242b 1px,#0000 1px);background-size:24px 24px;position:absolute;inset:0}.scene-canvas{display:block;position:absolute;inset:0}.scene-canvas-host.is-pan-ready .scene-canvas{cursor:grab!important}.scene-canvas-host.is-panning .scene-canvas{cursor:grabbing!important}.canvas-tools{z-index:3;position:absolute;top:10px;right:10px}.canvas-tools button{border:1px solid var(--line);background:var(--panel);width:28px;height:28px;color:var(--muted);cursor:pointer;border-radius:4px;place-items:center;padding:0;display:inline-grid}.canvas-tools button:hover:not(:disabled){border-color:var(--line-strong);background:var(--panel-raised);color:var(--text)}.canvas-status{border:1px solid var(--line);max-width:min(520px,100% - 48px);color:var(--muted);background:#15181e;border-radius:4px;padding:7px 10px;font-size:12px;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.inspector-panel{min-height:0}.inspector-heading{border-bottom:1px solid var(--line);justify-content:space-between;align-items:center;min-height:54px;padding:8px 12px;display:flex}.inspector-heading div{gap:3px;min-width:0;display:grid}.inspector-heading strong{text-overflow:ellipsis;white-space:nowrap;font-size:13px;overflow:hidden}.inspector-heading small{color:var(--muted);font-size:10px}.inspector-section-title{border-bottom:1px solid var(--line);height:28px;padding:9px 12px 0}.property-row{border-bottom:1px solid #21252d;grid-template-columns:minmax(0,1fr);min-height:34px;padding:3px 8px 3px 12px;display:grid}.property-row.is-paired{grid-template-columns:repeat(2,minmax(0,1fr));gap:6px}.property-field{grid-template-columns:minmax(70px,.8fr) minmax(120px,1.4fr);align-items:center;min-width:0;display:grid}.property-row.is-paired .property-field{grid-template-columns:max-content minmax(0,1fr);align-items:center;gap:4px}.property-row.is-paired .property-field>span{font-size:10px}.property-row.is-paired .property-control{grid-template-columns:minmax(0,1fr) 20px;gap:2px}.property-row.is-paired .reset-button{width:20px}.property-field>span{color:var(--text);text-overflow:ellipsis;white-space:nowrap;font-size:11px;overflow:hidden}.property-field>span.inherited{color:var(--muted)}.property-field.is-image-drop-candidate{box-shadow:inset 2px 0 var(--success);cursor:copy;background:#162b24}.property-field.is-image-drop-candidate:hover{background:#1b372d}.property-field.is-image-drop-candidate .property-control input[type=text]{border-color:var(--success)}.property-control{grid-template-columns:minmax(0,1fr) 24px;align-items:start;gap:3px;display:grid}.node-id-control{grid-template-columns:minmax(0,1fr)}.property-value{gap:3px;min-width:0;display:grid}.property-control input[type=text],.property-control input[type=number],.property-control select{border:1px solid var(--line-strong);background:var(--control);width:100%;min-width:0;height:25px;color:var(--text);border-radius:3px;outline:none;padding:0 7px;font-size:11px}.property-control input.resource-reference{cursor:alias}.property-control input:focus,.property-control select:focus{border-color:var(--focus)}.property-control input[type=text].is-invalid,.property-control input[type=text].is-invalid:focus{border-color:var(--danger)}.property-control input:disabled,.property-control select:disabled{color:#9ca6b5;cursor:default;opacity:1;background:#1b1f26;border-color:#303640}.property-control input[type=checkbox]{width:15px;height:15px;accent-color:var(--focus)}.property-control input[type=color]{border:1px solid var(--line-strong);background:var(--control);border-radius:3px;width:34px;height:24px;padding:2px}.reset-button{width:24px;height:24px}.binding-source{color:#8eb8e8;text-overflow:ellipsis;white-space:nowrap;align-items:center;gap:4px;min-width:0;font-size:10px;display:flex;overflow:hidden}.inline-error,.global-error{color:#ffd1d1;margin:0;font-size:11px}.inline-error{background:#2d1b20;border-bottom:1px solid #4f292f;padding:9px 12px}.global-error{background:#321e23;border:1px solid #66343c;border-radius:4px;max-width:min(520px,100vw - 24px);padding:9px 11px;position:fixed;bottom:12px;right:12px}@media (width<=860px){.workspace{grid-template-columns:190px minmax(320px,1fr) 270px}.topbar{grid-template-columns:190px minmax(0,1fr) auto 100px}}