@vgai/editor 0.4.0 → 0.4.1
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.
- package/dist/assets/{axe-BJjvBeOZ.js → axe-N4cNyzfs.js} +1 -1
- package/dist/assets/{browserAll-Dn0pgD87.js → browserAll-BIBT0Z2H.js} +1 -1
- package/dist/assets/{create-runtime-BF9OD-U8.js → create-runtime-DxLhdk4U.js} +1 -1
- package/dist/assets/{game-u6c2Patu.js → game-4NbNRROm.js} +1 -1
- package/dist/assets/{game-umrHIqFB.js → game-B3UH5LjS.js} +1 -1
- package/dist/assets/{game-BR0GBNgF.js → game-ByxRLJi1.js} +1 -1
- package/dist/assets/{game-DeTGdgYt.js → game-CJ5BqOYG.js} +1 -1
- package/dist/assets/{game-DQxhCYsZ.js → game-CSJm1kwB.js} +1 -1
- package/dist/assets/{game-CLNm2g0y.js → game-D9Mo4L3Q.js} +1 -1
- package/dist/assets/{game-B346oj_f.js → game-DJmU9BQF.js} +1 -1
- package/dist/assets/{game-BCNN63uV.js → game-ZqGLgxRj.js} +1 -1
- package/dist/assets/{game-loop-t5W_oqxz.js → game-loop-9YP76JB1.js} +1 -1
- package/dist/assets/{game-source-DzE9taML.js → game-source-DLKG9pmj.js} +1 -1
- package/dist/assets/{index-DbQzGLxv.js → index-8A4JLNIp.js} +902 -892
- package/dist/assets/{index-CgcH1RpF.js → index-Brzr17q0.js} +1 -1
- package/dist/assets/{index-D3tcNB2T.js → index-CnKtvrru.js} +1 -1
- package/dist/assets/{index-Fc8Ezr20.js → index-D-WR11Jw.js} +1 -1
- package/dist/assets/index-DiUacMXR.css +1 -0
- package/dist/assets/{ingest-siblings-CW_xbvrF.js → ingest-siblings-Cmx39OBK.js} +1 -1
- package/dist/assets/{mount-manifest-DgUscyaD.js → mount-manifest-kzdZgkkc.js} +1 -1
- package/dist/assets/{react-18-C4tVCii_.js → react-18-DvWsdwa_.js} +1 -1
- package/dist/assets/webworkerAll-C9GR-KrR.js +1 -0
- package/dist/assets/{world-documents-BSaA5YIF.js → world-documents-DM_aIMAW.js} +1 -1
- package/dist/index.html +2 -2
- package/dist-server/packaged.mjs +27125 -1075
- package/package.json +2 -2
- package/server/asset-history-snapshots.ts +189 -0
- package/server/asset-library-routes.ts +404 -53
- package/server/catalog-import-recipe.ts +97 -0
- package/server/catalog-reimport.ts +141 -0
- package/server/cloud-asset-catalog.ts +71 -5
- package/server/dev.ts +1 -1
- package/server/editor-server.ts +106 -51
- package/server/editor-sse.ts +5 -0
- package/server/generative-execution-context.ts +45 -0
- package/server/model-import-conversion.ts +345 -0
- package/server/packaged.ts +1 -1
- package/server/project-hmr-files.ts +3 -5
- package/server/project-output-writer.ts +440 -36
- package/server/project-tools.ts +529 -0
- package/server/server-utils.ts +14 -11
- package/src/EditorContext.tsx +4 -4
- package/src/action-registry.ts +12 -0
- package/src/asset-editor-context.tsx +9 -0
- package/src/asset-events.ts +3 -15
- package/src/asset-selection.ts +3 -0
- package/src/asset-workflow/asset-capabilities.ts +40 -0
- package/src/asset-workflow/asset-import-jobs.ts +108 -0
- package/src/asset-workflow/asset-library-query.ts +8 -1
- package/src/asset-workflow/asset-workflow-quality.ts +2 -0
- package/src/asset-workflow/import-contract.ts +2 -0
- package/src/asset-workflow/model-inspection.ts +92 -1
- package/src/asset-workflow/preview-resource-lifetime.ts +44 -0
- package/src/asset-workflow/project-asset-commands.ts +1 -0
- package/src/asset-workflow/project-asset-health.ts +3 -6
- package/src/asset-workflow/project-asset-operations.ts +119 -4
- package/src/command-listener.ts +37 -9
- package/src/components/ApplicationMenus.tsx +13 -15
- package/src/components/AssetBrowser.tsx +301 -26
- package/src/components/AssetImportDetails.tsx +207 -92
- package/src/components/AssetImportJobStatus.tsx +55 -0
- package/src/components/CenterDocuments.tsx +28 -1
- package/src/components/CommandPalette.tsx +2 -2
- package/src/components/DefaultEditorLayout.tsx +4 -0
- package/src/components/InspectorToolSection.tsx +12 -10
- package/src/components/OnlineAssetBrowser.tsx +197 -11
- package/src/components/ToolHost.tsx +8 -8
- package/src/components/ViewportOverlay.tsx +13 -26
- package/src/components/ViewportPanel.tsx +19 -14
- package/src/components/ViewportShadingMenu.tsx +103 -0
- package/src/components/WorkspaceDock.tsx +103 -17
- package/src/components/asset-documents.tsx +38 -11
- package/src/components/asset-editor-persistence.ts +300 -5
- package/src/components/asset-selection-section.tsx +83 -9
- package/src/components/asset-viewers/AudioViewer.tsx +4 -7
- package/src/components/asset-viewers/ModelViewer.tsx +168 -5
- package/src/components/asset-viewers/OnlineAssetDetail.tsx +52 -12
- package/src/components/asset-viewers/SourceAssetViewer.tsx +7 -26
- package/src/components/asset-workflow.css +30 -3
- package/src/components/primitives/editor-icons.ts +1 -0
- package/src/components/project-tool-documents.tsx +298 -0
- package/src/components/status-contributions.tsx +38 -0
- package/src/components/tool-documents.tsx +20 -17
- package/src/components/tool-schema-form.tsx +258 -0
- package/src/components/workspace-dock.css +16 -0
- package/src/editor-api.ts +159 -22
- package/src/editor-store.ts +6 -5
- package/src/editor-viewport.ts +12 -7
- package/src/game-viewport-state.ts +28 -0
- package/src/model-thumbnail.ts +97 -9
- package/src/play-mode.ts +30 -3
- package/src/project-tool-discovery.ts +5 -5
- package/src/{project-operations.ts → project-tools.ts} +39 -26
- package/src/scene-sync.ts +0 -67
- package/src/storage/handle-storage.ts +5 -1
- package/src/storage/http-storage.ts +7 -2
- package/src/storage/mem-storage.ts +7 -1
- package/src/storage/types.ts +2 -0
- package/src/theme-css.ts +17 -7
- package/src/tool-loader.ts +152 -241
- package/src/viewport-shading-boundary.ts +15 -0
- package/src/widgets/index.ts +2 -1
- package/src/workspace-dock-controller.ts +8 -0
- package/src/workspace-document-registry.ts +4 -4
- package/src/workspace-state-persistence.ts +36 -10
- package/template/.claude/skills/editor/SKILL.md +13 -3
- package/template/AGENTS.md +100 -83
- package/template/package.json +16 -0
- package/template/public/scenes/default.vscn.json +1 -2
- package/template/scripts/playtest.ts +7 -37
- package/template/server/rooms/game-room.ts +2 -2
- package/template/src/data/README.md +3 -2
- package/template/src/data/tuning.data.json +1 -3
- package/template/src/data/tuning.schema.json +0 -12
- package/template/src/data/tuning.schema.ts +2 -9
- package/template/src/data/tuning.ts +1 -1
- package/template/src/scripts/registry.ts +0 -3
- package/template/src/tools/README.md +151 -16
- package/template/src/tools/autoplay.tool.ts +31 -0
- package/template/src/tools/autoplay.ts +15 -0
- package/template/src/tools/tuning.document.tsx +107 -0
- package/template/src/tools/tuning.tool.ts +24 -0
- package/template/src/tools/tuning.ts +9 -0
- package/template/src/ui/Button.stories.tsx +1 -1
- package/template/tests/acceptance/example.spec.ts +4 -59
- package/template/vgai.game.json +1 -1
- package/dist/assets/index-bAGhEnnO.css +0 -1
- package/dist/assets/webworkerAll-BA4aq7xq.js +0 -1
- package/dist/project-scripts.bundle.js +0 -3917
- package/server/project-operations.ts +0 -343
- package/src/components/project-operation-documents.tsx +0 -226
- package/template/src/operations/README.md +0 -88
- package/template/src/scripts/components/data-spinner.ts +0 -86
- package/template/src/scripts/components/spin-lap-math.ts +0 -27
- package/template/src/tools/example.tool.tsx +0 -97
- package/template/src/tools/spin.tool.tsx +0 -101
- package/template/tests/logic/example.test.ts +0 -31
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as c,m as l,l as f,b as m,R as p,f as h,V as g}from"./index-
|
|
1
|
+
import{a as c,m as l,l as f,b as m,R as p,f as h,V as g}from"./index-8A4JLNIp.js";import{createGameRuntime as y}from"./create-runtime-DxLhdk4U.js";import"./game-loop-9YP76JB1.js";function v(e){if(e.determinism?.seededRandom!==!0)return;const t=e.url?E(e.url):void 0;return e.explicitSeed??t??e.determinism.defaultSeed}function E(e){const t=new URLSearchParams(e.search).get(p);if(t===null||t==="")return;const r=Number(t);return Number.isFinite(r)?r:void 0}function b(){return typeof window<"u"}function R(e){if(typeof e!="object"||e===null)return!1;const t=e.roots;return!Array.isArray(t)||t.length===0?!1:t.every(r=>{if(typeof r!="object"||r===null)return!1;const n=r.adapter;if(typeof n!="object"||n===null)return!1;const i=n.type;return i==="builtin"||i==="module"||i==="ingest"})}function M(e){return R(e)?e:f(e)}function $(e,t){if(t?.adapter)return t.adapter;if(e.adapter.type==="module")throw new Error(`mountManifestWorlds: world "${e.id}" (threejs) declares a { module } adapter ("${e.adapter.module}") — mountManifestWorlds never imports an arbitrary module path itself (no \`/@fs/\`, no dev server). Import the module yourself and supply the constructed adapter via entries["${e.id}"] = { kind: 'threejs', adapter }.`);if(e.adapter.type==="ingest")throw new Error(`mountManifestWorlds: world "${e.id}" (threejs) declares an { ingest } adapter — ingest roots require the editor's dev-server-backed mount machinery (an EditorStore plus iframe/DOM capture, see adapter-resolver.ts's resolveIngestThreeAdapter) and are not supported by mountManifestWorlds (docs/WAVE3-ADAPTER-PLUMBING-DESIGN.md D-Z7 — no porting aids, no hosted ingest routes).`);if(e.entry!==void 0){if(!t?.setup)throw new Error(`mountManifestWorlds: world "${e.id}" (threejs) declares \`entry\` "${e.entry}" — supply entries["${e.id}"] = { kind: 'threejs', setup } (the entry module's exported \`setup\` function) or { kind: 'threejs', adapter } for full control. Got ${t===void 0?"no entry at all":"an entry with neither `setup` nor `adapter`"}.`);return h(e.id,t.setup)}if(e.scene!==void 0)return new g({id:e.id,scenePath:e.scene,componentRegistry:t?.componentRegistry});throw new Error(`mountManifestWorlds: world "${e.id}" is default-three with neither \`scene\` nor \`entry\` — this should have been rejected by manifest validation.`)}function j(e,t){if(t?.adapter)return t.adapter;throw new Error(`mountManifestWorlds: world "${e.id}" (pixijs) has no entries["${e.id}"] — a pixijs world always needs a caller-supplied, already-constructed adapter (entries["${e.id}"] = { kind: 'pixijs', adapter }, e.g. \`new PixiSceneGameAdapter(...)\` built from your own already-imported '@engine/world2d') — mountManifestWorlds never value-imports pixi.js (mirrors create-runtime.ts's own pixi-free-core discipline).`)}function A(e,t){if(t?.adapter)return t.adapter;throw new Error(`mountManifestWorlds: world "${e.id}" (react) has no entries["${e.id}"] — a react world always needs a caller-supplied, already-constructed \`ReactRootAdapter\` (entries["${e.id}"] = { kind: 'react', adapter }, mounting via your own already-imported react-dom \`createRoot\` + your own \`<GameProvider>\`) — mountManifestWorlds never value-imports react/react-dom (mirrors create-runtime.ts's own react-free-core discipline; see docs/REACT-STATE-BRIDGE.md §2-3).`)}function S(e,t){if(t!==void 0&&t.kind!==e.surface)throw new Error(`mountManifestWorlds: entries["${e.id}"] declares kind "${t.kind}" but the manifest's root "${e.id}" uses surface "${e.surface}" — fix the entries key (or the manifest) so the two agree.`);const r={id:e.id,zOrder:e.zOrder,pausable:e.pausable,loop:e.loop};return e.surface==="threejs"?{...r,kind:"threejs",adapter:$(e,t)}:e.surface==="pixijs"?{...r,kind:"pixijs",adapter:j(e,t)}:e.surface==="react"?{...r,kind:"react",adapter:A(e,t)}:m(e.surface,"mountManifestWorlds")}async function D(e){const t=M(e.manifest);if(t.roots.length===0)throw new Error("mountManifestWorlds: manifest declares no roots — nothing to mount.");const r=e.entries??{},n=t.roots.map(s=>S(s,r[s.id])),i=e.seedUrl??(b()?window.location:void 0),d=v({determinism:t.determinism,explicitSeed:e.seed,url:i}),a=await y({container:e.container,roots:n,width:e.width??t.resolution?.width,height:e.height??t.resolution?.height,headless:e.headless,seed:d});t.determinism?.seededRandom;const o=c(a.game);if(o){t.server&&o.setRoomDeclared(!0);const s=l({registry:o,manifest:t,url:e.debugBridge?.url,window:e.debugBridge?.window});if(s){const u=a.stop;a.stop=()=>{s.uninstall(),u()}}}return a}export{D as mountManifestWorlds,v as resolveDeterminismSeed,M as resolveManifest};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{B as s,z as l}from"./index-
|
|
1
|
+
import{B as s,z as l}from"./index-8A4JLNIp.js";var n=new Map;function a(){return globalThis.IS_REACT_ACT_ENVIRONMENT}var m=({callback:e,children:r})=>{let t=s.useRef();return s.useLayoutEffect(()=>{t.current!==e&&(t.current=e,e())},[e]),r};typeof Promise.withResolvers>"u"&&(Promise.withResolvers=()=>{let e=null,r=null;return{promise:new Promise((t,o)=>{e=t,r=o}),resolve:e,reject:r}});var E=async(e,r,t)=>{let o=await c(r,t);if(a()){o.render(e);return}let{promise:u,resolve:i}=Promise.withResolvers();return o.render(s.createElement(m,{callback:i},e)),u},p=(e,r)=>{let t=n.get(e);t&&(t.unmount(),n.delete(e))},c=async(e,r)=>{let t=n.get(e);return t||(t=l.createRoot(e,r),n.set(e,t)),t};export{E as renderElement,p as unmountElement};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ag as a,bV as s,bW as e,bX as t}from"./index-8A4JLNIp.js";a.add(s,e);a.add(t);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{am as O,an as ie,ao as le,s as de,o as W,k as R,n as ce,ap as J,D as G,aq as ue,ar as pe,as as he,at as fe,y as me,au as we,av as ge,aw as ye,ax as be,ay as ve,az as Ie,aA as ee,aB as te,aC as xe,aD as Se,aE as Ee,c as Ce,B as I,aF as ke,aG as j,aH as h,aI as Pe,aJ as Me,aK as V,aL as F,aM as $e,aN as Re,aO as ze,aP as We,aQ as K,aR as De,aS as q,aT as X,aU as Ae,aV as je,aW as Oe,aX as Te,aY as z,aZ as Be}from"./index-DbQzGLxv.js";import{c as Ve,a as Fe}from"./game-loop-t5W_oqxz.js";const _e={width:null,height:null};let T=_e;const H=new Set;function oe(){return T}function L(e,o){const n=e===null?null:Math.max(1,Math.round(e)),r=o===null?null:Math.max(1,Math.round(o));if(!(T.width===n&&T.height===r)){T={width:n,height:r};for(const a of H)a()}}function Ge(){L(null,null)}function re(e){return H.add(e),()=>H.delete(e)}const U=new Map;function He(e,o){return`${e}\0${o}`}function Le(e){const o=e.title?.split("/").filter(Boolean).at(-1)?.trim();if(o)return o;const n=e.modulePath.split("/").pop()??e.modulePath;return n.replace(/\.stories\.[^.]+$/i,"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/[-_]+/g," ").trim()||n}const Ne=1;function ne(e){const o=[];for(const{worldId:n,adapter:r}of e.childAdapters()){if(!(r instanceof O))continue;const a=r.inspector.get(n,"kind");a!=="react"&&a!=="pixijs"||r.inspector.get(n,"reason")!==void 0||o.push({worldId:n,kind:a,path:r.inspector.get(n,"path"),zOrder:Number(r.inspector.get(n,"zOrder")??0),pausable:r.inspector.get(n,"pausable")!==!1})}return o}function Ze(e){return ne(e)}function Ke(){const e=Ve({fixedTimestep:.016666666666666666,maxSubSteps:8,update:()=>{}});return Ce({loop:e,assets:Fe()})}class qe extends I.Component{constructor(){super(...arguments),this.state={crashed:!1}}static getDerivedStateFromError(){return{crashed:!0}}componentDidCatch(o){this.props.onCaught(o)}render(){return this.state.crashed?null:this.props.children}}function Xe(e,o){return{id:e,surface:"react",description:void 0,adapter:{type:"builtin",identity:"react",surface:"react"},scene:void 0,entry:o,zOrder:0,pausable:!0,loop:"gated",capabilities:{local:"first-party",hosted:"first-party"}}}function se(e,o){e.style.display=xe(o)?"none":"block",e.style.pointerEvents=Se(o)?"auto":"none"}function Ue(e,o,n){const r=document.createElement("div");return r.dataset.worldId=o,r.style.position="absolute",r.style.top="0",r.style.left="0",r.style.width="100%",r.style.height="100%",r.style.zIndex=String(n),r.style.contain="layout paint",se(r,o),N(r),e.appendChild(r),r}function N(e){e.style.transform=ee(te())??"",e.style.transformOrigin="0 0";const o=oe();e.style.width=o.width===null?"100%":`${o.width}px`,e.style.height=o.height===null?"100%":`${o.height}px`}async function Ye(e,o,n,r){if(!e.path)throw new Error(`design-time react layer "${e.worldId}": no \`entry\` declared — nothing to mount.`);await pe({rootPath:n});const a=he(e.worldId),s=fe(e.worldId);if(s){const t=He(n,e.worldId),d=U.get(t),u=a.find(c=>c.id===d)??s;let P=!1,y=null;const S=async(c,b=c.args)=>{const E=await Ee(o,c.modulePath,c.name,c.Component,b);if(E){if(P){E.unmount();return}y=E,r.notifyIngestEdit()}};if(await S(u),!y)throw new Error(`design-time react root "${e.worldId}": default CSF story "${u.name}" was superseded before it mounted.`);const A=new Map(a.map(c=>[c.id,c])),B=new Map;for(const c of a){const b=B.get(c.modulePath);b?b.push(c):B.set(c.modulePath,[c])}const Z=new G(o,r,{worldId:e.worldId,portableStories:a.map(c=>({id:c.id,label:c.label,args:c.args})),portableDocuments:[...B.entries()].map(([c,b])=>({id:`portable-document:${c}`,label:Le(b[0]),path:c,storyIds:b.map(E=>E.id)})),activePortableStoryId:u.id,onPortableStoryApplied:c=>{const b=(c?A.get(c):null)??s;U.set(t,b.id),S(b).catch(E=>{R.error(`[design-time-layers] React root "${e.worldId}" failed applying portable story "${b.name}": ${W(E)}`,"authoring")})},onPortableStoryArgsChanged:(c,b)=>{const E=A.get(c);E&&S(E,b).catch(ae=>{R.error(`[design-time-layers] React root "${e.worldId}" failed updating portable story "${E.name}" args: ${W(ae)}`,"authoring")})}});return{adapter:Z,dispose:()=>{P=!0,Z.disposeReactRootAdapter(),y?.unmount()}}}R.warn(`[design-time-layers] React root "${e.worldId}" has no portable CSF preview. Add a *.stories.tsx module with parameters.vgai.root set to this root id. Falling back to the deprecated inert-Game preview for compatibility.`,"authoring");const f=Xe(e.worldId,e.path),v=await me(f,n),C=await we(n,e.worldId),{createElement:l,createRoot:p,flushSync:i}=await ge(),m=Ke(),g=[ye(e.worldId)??{}],w={},x=p(o),M={entryStory:null,isolation:null},$=t=>{const{entryStory:d,isolation:u}=M,P=u?u.story:d,y=u?w?.[u.componentKey]:void 0,S=u?y?l(y,{...P?.props??{}}):null:l(v,{...P?.props??{}});x.render(l(qe,{key:u?`isolate:${u.componentKey}:${u.story?.id??""}`:P?`story:${P.id}`:"__none__",onCaught:t,children:l(C,{game:m},S)}))};let k=null;if(i(()=>{$(t=>{k=t})}),k!==null)throw x.unmount(),k instanceof Error?k:new Error(String(k));const D=new G(o,r,{storySources:g,worldId:e.worldId,onStoryApplied:t=>{M.entryStory=t,$(d=>{R.error(`[design-time-layers] world "${e.worldId}" crashed applying story "${t?.id??"(cleared)"}": ${W(d)}`,"authoring")})},onIsolate:t=>{M.isolation=t,$(d=>{R.error(`[design-time-layers] world "${e.worldId}" crashed isolating "${t?.componentKey??"(cleared)"}": ${W(d)}`,"authoring")})}});return{adapter:D,dispose:()=>{D.disposeReactRootAdapter(),x.unmount()}}}function Qe(e){const o=e.getBoundingClientRect();return{width:Math.max(1,Math.round(o.width)||e.clientWidth||300),height:Math.max(1,Math.round(o.height)||e.clientHeight||200)}}async function Je(e,o,n,r){if(!e.path)throw new Error(`design-time pixi layer "${e.worldId}": no \`scene\` declared — nothing to mount (B1 display-only mount supports scene-based pixi roots only, not \`entry\`).`);const a=await be(e.path),s=await ve(r),f=document.createElement("canvas");f.style.width="100%",f.style.height="100%",f.style.display="block",o.appendChild(f);const{width:v,height:C}=Qe(n),p=await new Ie({id:e.worldId,sceneData:a,registry:s}).mount({canvas:f,width:v,height:C,transparent:!0});return p.update?.(0),{dispose:()=>p.dispose(),pick:(m,g)=>{const w=f.getBoundingClientRect();if(w.width===0||w.height===0)return null;const x=p.ctx.app.renderer.screen,M=(m-w.left)/w.width*x.width,$=(g-w.top)/w.height*x.height;for(const k of p.stage.children)if(k.getBounds().containsPoint(M,$))return e.worldId;return null}}}let _=!1;function Y(){_||(_=!0,queueMicrotask(()=>{_=!1,window.dispatchEvent(new CustomEvent(ue))}))}function et(e,o,n,r){if(ie(),Ge(),n.playState!=="stopped"){let t=!1,d=!1;const u=n.subscribe(()=>{t||d||n.playState!=="stopped"||(d=!0,t||Y())});return()=>{t=!0,u()}}const a=le()?.rootPath,s=r?[...r]:ne(o);if(s.length===0||!a)return()=>{};const v=de(s.map(t=>({id:t.worldId,zOrder:t.zOrder}))).map(t=>s.find(d=>d.worldId===t.id)),C=new Map(v.map(t=>[t.worldId,t])),l=new Map,p=[],i=new Set;let m=!1,g=!1,w=!1;function x(){for(const t of p.splice(0))try{t()}catch(d){R.error(`[design-time-layers] dispose failed: ${d}`,"authoring")}for(const t of l.values())t.remove();l.clear()}function M(){x();for(const t of i){const d=C.get(t);if(!d)continue;const u={id:d.worldId,kind:d.kind,entryOrScenePath:d.path,zOrder:d.zOrder,pausable:d.pausable};o.replaceChild(t,new O(n,u,"Design-time layer suspended by play mode — Stop restores it."))}i.clear(),n.notifyIngestEdit()}v.forEach((t,d)=>{const u=Ue(e,t.worldId,Ne+d);l.set(t.worldId,u),(t.kind==="react"?Ye(t,u,a,n):Je(t,u,e,a)).then(y=>{if(m||g){y.dispose();return}if(y.adapter)o.replaceChild(t.worldId,y.adapter),i.add(t.worldId);else if(y.pick){const S={id:t.worldId,kind:t.kind,entryOrScenePath:t.path,zOrder:t.zOrder,pausable:t.pausable};o.replaceChild(t.worldId,new O(n,S,void 0,y.pick)),i.add(t.worldId)}p.push(y.dispose),n.notifyIngestEdit()}).catch(y=>{if(u.remove(),l.delete(t.worldId),m||g)return;const S=W(y);R.error(`[design-time-layers] world "${t.worldId}" (${t.kind}) failed to mount: ${S}`,"authoring");const A={id:t.worldId,kind:t.kind,entryOrScenePath:t.path,zOrder:t.zOrder,pausable:t.pausable};o.replaceChild(t.worldId,new O(n,A,S)),ce({worldId:t.worldId,kind:t.kind,identity:t.kind==="react"?"default-react":"default-pixi",message:S}),n.notifyIngestEdit()})});const $=J(()=>{for(const t of l.values())N(t)}),k=re(()=>{for(const t of l.values())N(t)}),D=n.subscribe(()=>{if(!g&&n.playState!=="stopped"){g=!0,M();return}if(g&&!w&&n.playState==="stopped"&&!m){w=!0,m||Y();return}if(!g){for(const[t,d]of l)se(d,t);for(const{worldId:t,adapter:d}of o.childAdapters()){if(!i.has(t)||!(d instanceof G))continue;const u=d.isolatedNodeId;u&&!n.selectedEntityIds.has(u)&&d.stories.isolate?.(null)}}});return()=>{m=!0,D(),$(),k(),x()}}const Q={fill:null,desktop:{width:1440,height:900},tablet:{width:768,height:1024},mobile:{width:390,height:844}};function tt({containerRef:e,context:o}){const n=ke();I.useSyncExternalStore(n.subscribe,n.getSnapshot);const r=I.useSyncExternalStore(J,te),a=I.useSyncExternalStore(re,oe),s=I.useCallback(l=>{const p=e.current;if(!p)return;const i=Math.min(4,Math.max(.1,l)),m=p.clientWidth/2,g=p.clientHeight/2,w=(m-r.x)/r.zoom,x=(g-r.y)/r.zoom;j(m-w*i,g-x*i,i)},[e,r]),f=I.useCallback(()=>{const l=e.current,p=[...n.selectedEntityIds].at(-1);if(!l||!p)return;const i=o?.adapter.rects?.rect(p);if(!i||i.width<=0||i.height<=0)return;const m=Math.max(1,l.clientWidth-96),g=Math.max(1,l.clientHeight-96),w=Math.min(4,Math.max(.1,Math.min(m/i.width,g/i.height)));j(l.clientWidth/2-(i.x+i.width/2)*w,l.clientHeight/2-(i.y+i.height/2)*w,w)},[e,o,n]),v=I.useCallback(l=>{const p=e.current,i=Q[l];if(!p||i===null){L(null,null),j(0,0,1);return}L(i.width,i.height);const m=Math.min(1,Math.max(.1,Math.min((p.clientWidth-96)/i.width,(p.clientHeight-96)/i.height)));j((p.clientWidth-i.width*m)/2,(p.clientHeight-i.height*m)/2,m)},[e]);if(o?.kind!=="react"||!o.adapter.rects)return null;const C=Object.entries(Q).find(([,l])=>l===null?a.width===null:l.width===a.width&&l.height===a.height)?.[0]??"fill";return h.jsxs(h.Fragment,{children:[a.width!==null&&a.height!==null&&h.jsx("div",{"data-testid":"react-canvas-device-frame",style:{position:"absolute",left:0,top:0,zIndex:0,width:a.width,height:a.height,transform:ee(r),transformOrigin:"0 0",pointerEvents:"none",background:"#fff",boxShadow:"0 0 0 1px #ffffff40, 0 8px 30px #0009"}}),h.jsxs(Pe,{label:"React canvas view","data-testid":"react-canvas-zoom-controls",className:"vgai-react-canvas-controls",children:[h.jsxs(Me,{"aria-label":"Responsive viewport",title:"Responsive viewport",value:C,onChange:l=>v(l.target.value),className:"vgai-react-viewport-select",children:[h.jsx("option",{value:"fill",children:"Fill"}),h.jsx("option",{value:"desktop",children:"Desktop · 1440×900"}),h.jsx("option",{value:"tablet",children:"Tablet · 768×1024"}),h.jsx("option",{value:"mobile",children:"Mobile · 390×844"})]}),h.jsx(V,{"aria-label":"Zoom out",title:"Zoom out",size:"comfortable",onClick:()=>s(r.zoom/1.2),children:h.jsx(F,{icon:$e,size:"md"})}),h.jsxs(Re,{variant:"ghost","aria-label":"Reset zoom to 100%",title:"Reset zoom to 100%",size:"comfortable",onClick:()=>s(1),children:[Math.round(r.zoom*100),"%"]}),h.jsx(V,{"aria-label":"Zoom in",title:"Zoom in",size:"comfortable",onClick:()=>s(r.zoom*1.2),children:h.jsx(F,{icon:ze,size:"md"})}),h.jsx(V,{"aria-label":"Zoom to selection",title:"Zoom to selection",size:"comfortable",onClick:f,children:h.jsx(F,{icon:We,size:"md"})})]})]})}function ot(e){return`workspace:world:${e}`}function rt({active:e,composite:o,descriptor:n,store:r}){const a=I.useRef(null),s=I.useRef(null);I.useSyncExternalStore(r.subscribe,r.getSnapshot),I.useEffect(()=>{!e||s.current||!a.current||(s.current=et(a.current,o,r,[n]))},[e,o,n,r]),I.useEffect(()=>()=>{s.current?.(),s.current=null},[]);const f=Oe(Te(r),r.selectedEntityIds),v=f?.worldId===n.worldId?f:null;return h.jsxs("div",{ref:a,"data-testid":`world-document:${n.worldId}`,style:{position:"absolute",inset:0,overflow:"hidden",pointerEvents:"auto",backgroundColor:z.surface.raised,backgroundImage:`linear-gradient(45deg, ${z.surface.chrome} 25%, transparent 25%, transparent 75%, ${z.surface.chrome} 75%), linear-gradient(45deg, ${z.surface.chrome} 25%, transparent 25%, transparent 75%, ${z.surface.chrome} 75%)`,backgroundPosition:"0 0, 8px 8px",backgroundSize:"16px 16px"},children:[h.jsx(Be,{}),h.jsx(tt,{containerRef:a,context:v})]})}function at(e,o){const n=je(),r=[],a=[];for(const s of o.childAdapters())s.role==="world"&&s.kind==="threejs"&&a.push(K(s.worldId,X));for(const s of Ze(o)){const f=ot(s.worldId);a.push(K(s.worldId,f)),r.push(f);const v=C=>h.jsx(rt,{...C,composite:o,descriptor:s,store:e});De({id:f,title:s.worldId,kind:"world",provenance:{rootId:s.worldId,...s.path?{sourcePath:s.path}:{}},Content:v,closeable:!1,onActivate:()=>e.setActiveViewportTab("scene")})}return n?q(n):q(X),()=>{for(const s of a)s();for(const s of r)Ae(s,{discardDirty:!0})}}export{at as installWorldDocuments,ot as worldDocumentId};
|
|
1
|
+
import{am as O,an as ie,ao as le,s as de,o as W,k as R,n as ce,ap as J,D as G,aq as ue,ar as pe,as as he,at as fe,y as me,au as we,av as ge,aw as ye,ax as be,ay as ve,az as Ie,aA as ee,aB as te,aC as xe,aD as Se,aE as Ee,c as Ce,B as I,aF as ke,aG as j,aH as h,aI as Pe,aJ as Me,aK as V,aL as F,aM as $e,aN as Re,aO as ze,aP as We,aQ as K,aR as De,aS as q,aT as X,aU as Ae,aV as je,aW as Oe,aX as Te,aY as z,aZ as Be}from"./index-8A4JLNIp.js";import{c as Ve,a as Fe}from"./game-loop-9YP76JB1.js";const _e={width:null,height:null};let T=_e;const H=new Set;function oe(){return T}function L(e,o){const n=e===null?null:Math.max(1,Math.round(e)),r=o===null?null:Math.max(1,Math.round(o));if(!(T.width===n&&T.height===r)){T={width:n,height:r};for(const a of H)a()}}function Ge(){L(null,null)}function re(e){return H.add(e),()=>H.delete(e)}const U=new Map;function He(e,o){return`${e}\0${o}`}function Le(e){const o=e.title?.split("/").filter(Boolean).at(-1)?.trim();if(o)return o;const n=e.modulePath.split("/").pop()??e.modulePath;return n.replace(/\.stories\.[^.]+$/i,"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/[-_]+/g," ").trim()||n}const Ne=1;function ne(e){const o=[];for(const{worldId:n,adapter:r}of e.childAdapters()){if(!(r instanceof O))continue;const a=r.inspector.get(n,"kind");a!=="react"&&a!=="pixijs"||r.inspector.get(n,"reason")!==void 0||o.push({worldId:n,kind:a,path:r.inspector.get(n,"path"),zOrder:Number(r.inspector.get(n,"zOrder")??0),pausable:r.inspector.get(n,"pausable")!==!1})}return o}function Ze(e){return ne(e)}function Ke(){const e=Ve({fixedTimestep:.016666666666666666,maxSubSteps:8,update:()=>{}});return Ce({loop:e,assets:Fe()})}class qe extends I.Component{constructor(){super(...arguments),this.state={crashed:!1}}static getDerivedStateFromError(){return{crashed:!0}}componentDidCatch(o){this.props.onCaught(o)}render(){return this.state.crashed?null:this.props.children}}function Xe(e,o){return{id:e,surface:"react",description:void 0,adapter:{type:"builtin",identity:"react",surface:"react"},scene:void 0,entry:o,zOrder:0,pausable:!0,loop:"gated",capabilities:{local:"first-party",hosted:"first-party"}}}function se(e,o){e.style.display=xe(o)?"none":"block",e.style.pointerEvents=Se(o)?"auto":"none"}function Ue(e,o,n){const r=document.createElement("div");return r.dataset.worldId=o,r.style.position="absolute",r.style.top="0",r.style.left="0",r.style.width="100%",r.style.height="100%",r.style.zIndex=String(n),r.style.contain="layout paint",se(r,o),N(r),e.appendChild(r),r}function N(e){e.style.transform=ee(te())??"",e.style.transformOrigin="0 0";const o=oe();e.style.width=o.width===null?"100%":`${o.width}px`,e.style.height=o.height===null?"100%":`${o.height}px`}async function Ye(e,o,n,r){if(!e.path)throw new Error(`design-time react layer "${e.worldId}": no \`entry\` declared — nothing to mount.`);await pe({rootPath:n});const a=he(e.worldId),s=fe(e.worldId);if(s){const t=He(n,e.worldId),d=U.get(t),u=a.find(c=>c.id===d)??s;let P=!1,y=null;const S=async(c,b=c.args)=>{const E=await Ee(o,c.modulePath,c.name,c.Component,b);if(E){if(P){E.unmount();return}y=E,r.notifyIngestEdit()}};if(await S(u),!y)throw new Error(`design-time react root "${e.worldId}": default CSF story "${u.name}" was superseded before it mounted.`);const A=new Map(a.map(c=>[c.id,c])),B=new Map;for(const c of a){const b=B.get(c.modulePath);b?b.push(c):B.set(c.modulePath,[c])}const Z=new G(o,r,{worldId:e.worldId,portableStories:a.map(c=>({id:c.id,label:c.label,args:c.args})),portableDocuments:[...B.entries()].map(([c,b])=>({id:`portable-document:${c}`,label:Le(b[0]),path:c,storyIds:b.map(E=>E.id)})),activePortableStoryId:u.id,onPortableStoryApplied:c=>{const b=(c?A.get(c):null)??s;U.set(t,b.id),S(b).catch(E=>{R.error(`[design-time-layers] React root "${e.worldId}" failed applying portable story "${b.name}": ${W(E)}`,"authoring")})},onPortableStoryArgsChanged:(c,b)=>{const E=A.get(c);E&&S(E,b).catch(ae=>{R.error(`[design-time-layers] React root "${e.worldId}" failed updating portable story "${E.name}" args: ${W(ae)}`,"authoring")})}});return{adapter:Z,dispose:()=>{P=!0,Z.disposeReactRootAdapter(),y?.unmount()}}}R.warn(`[design-time-layers] React root "${e.worldId}" has no portable CSF preview. Add a *.stories.tsx module with parameters.vgai.root set to this root id. Falling back to the deprecated inert-Game preview for compatibility.`,"authoring");const f=Xe(e.worldId,e.path),v=await me(f,n),C=await we(n,e.worldId),{createElement:l,createRoot:p,flushSync:i}=await ge(),m=Ke(),g=[ye(e.worldId)??{}],w={},x=p(o),M={entryStory:null,isolation:null},$=t=>{const{entryStory:d,isolation:u}=M,P=u?u.story:d,y=u?w?.[u.componentKey]:void 0,S=u?y?l(y,{...P?.props??{}}):null:l(v,{...P?.props??{}});x.render(l(qe,{key:u?`isolate:${u.componentKey}:${u.story?.id??""}`:P?`story:${P.id}`:"__none__",onCaught:t,children:l(C,{game:m},S)}))};let k=null;if(i(()=>{$(t=>{k=t})}),k!==null)throw x.unmount(),k instanceof Error?k:new Error(String(k));const D=new G(o,r,{storySources:g,worldId:e.worldId,onStoryApplied:t=>{M.entryStory=t,$(d=>{R.error(`[design-time-layers] world "${e.worldId}" crashed applying story "${t?.id??"(cleared)"}": ${W(d)}`,"authoring")})},onIsolate:t=>{M.isolation=t,$(d=>{R.error(`[design-time-layers] world "${e.worldId}" crashed isolating "${t?.componentKey??"(cleared)"}": ${W(d)}`,"authoring")})}});return{adapter:D,dispose:()=>{D.disposeReactRootAdapter(),x.unmount()}}}function Qe(e){const o=e.getBoundingClientRect();return{width:Math.max(1,Math.round(o.width)||e.clientWidth||300),height:Math.max(1,Math.round(o.height)||e.clientHeight||200)}}async function Je(e,o,n,r){if(!e.path)throw new Error(`design-time pixi layer "${e.worldId}": no \`scene\` declared — nothing to mount (B1 display-only mount supports scene-based pixi roots only, not \`entry\`).`);const a=await be(e.path),s=await ve(r),f=document.createElement("canvas");f.style.width="100%",f.style.height="100%",f.style.display="block",o.appendChild(f);const{width:v,height:C}=Qe(n),p=await new Ie({id:e.worldId,sceneData:a,registry:s}).mount({canvas:f,width:v,height:C,transparent:!0});return p.update?.(0),{dispose:()=>p.dispose(),pick:(m,g)=>{const w=f.getBoundingClientRect();if(w.width===0||w.height===0)return null;const x=p.ctx.app.renderer.screen,M=(m-w.left)/w.width*x.width,$=(g-w.top)/w.height*x.height;for(const k of p.stage.children)if(k.getBounds().containsPoint(M,$))return e.worldId;return null}}}let _=!1;function Y(){_||(_=!0,queueMicrotask(()=>{_=!1,window.dispatchEvent(new CustomEvent(ue))}))}function et(e,o,n,r){if(ie(),Ge(),n.playState!=="stopped"){let t=!1,d=!1;const u=n.subscribe(()=>{t||d||n.playState!=="stopped"||(d=!0,t||Y())});return()=>{t=!0,u()}}const a=le()?.rootPath,s=r?[...r]:ne(o);if(s.length===0||!a)return()=>{};const v=de(s.map(t=>({id:t.worldId,zOrder:t.zOrder}))).map(t=>s.find(d=>d.worldId===t.id)),C=new Map(v.map(t=>[t.worldId,t])),l=new Map,p=[],i=new Set;let m=!1,g=!1,w=!1;function x(){for(const t of p.splice(0))try{t()}catch(d){R.error(`[design-time-layers] dispose failed: ${d}`,"authoring")}for(const t of l.values())t.remove();l.clear()}function M(){x();for(const t of i){const d=C.get(t);if(!d)continue;const u={id:d.worldId,kind:d.kind,entryOrScenePath:d.path,zOrder:d.zOrder,pausable:d.pausable};o.replaceChild(t,new O(n,u,"Design-time layer suspended by play mode — Stop restores it."))}i.clear(),n.notifyIngestEdit()}v.forEach((t,d)=>{const u=Ue(e,t.worldId,Ne+d);l.set(t.worldId,u),(t.kind==="react"?Ye(t,u,a,n):Je(t,u,e,a)).then(y=>{if(m||g){y.dispose();return}if(y.adapter)o.replaceChild(t.worldId,y.adapter),i.add(t.worldId);else if(y.pick){const S={id:t.worldId,kind:t.kind,entryOrScenePath:t.path,zOrder:t.zOrder,pausable:t.pausable};o.replaceChild(t.worldId,new O(n,S,void 0,y.pick)),i.add(t.worldId)}p.push(y.dispose),n.notifyIngestEdit()}).catch(y=>{if(u.remove(),l.delete(t.worldId),m||g)return;const S=W(y);R.error(`[design-time-layers] world "${t.worldId}" (${t.kind}) failed to mount: ${S}`,"authoring");const A={id:t.worldId,kind:t.kind,entryOrScenePath:t.path,zOrder:t.zOrder,pausable:t.pausable};o.replaceChild(t.worldId,new O(n,A,S)),ce({worldId:t.worldId,kind:t.kind,identity:t.kind==="react"?"default-react":"default-pixi",message:S}),n.notifyIngestEdit()})});const $=J(()=>{for(const t of l.values())N(t)}),k=re(()=>{for(const t of l.values())N(t)}),D=n.subscribe(()=>{if(!g&&n.playState!=="stopped"){g=!0,M();return}if(g&&!w&&n.playState==="stopped"&&!m){w=!0,m||Y();return}if(!g){for(const[t,d]of l)se(d,t);for(const{worldId:t,adapter:d}of o.childAdapters()){if(!i.has(t)||!(d instanceof G))continue;const u=d.isolatedNodeId;u&&!n.selectedEntityIds.has(u)&&d.stories.isolate?.(null)}}});return()=>{m=!0,D(),$(),k(),x()}}const Q={fill:null,desktop:{width:1440,height:900},tablet:{width:768,height:1024},mobile:{width:390,height:844}};function tt({containerRef:e,context:o}){const n=ke();I.useSyncExternalStore(n.subscribe,n.getSnapshot);const r=I.useSyncExternalStore(J,te),a=I.useSyncExternalStore(re,oe),s=I.useCallback(l=>{const p=e.current;if(!p)return;const i=Math.min(4,Math.max(.1,l)),m=p.clientWidth/2,g=p.clientHeight/2,w=(m-r.x)/r.zoom,x=(g-r.y)/r.zoom;j(m-w*i,g-x*i,i)},[e,r]),f=I.useCallback(()=>{const l=e.current,p=[...n.selectedEntityIds].at(-1);if(!l||!p)return;const i=o?.adapter.rects?.rect(p);if(!i||i.width<=0||i.height<=0)return;const m=Math.max(1,l.clientWidth-96),g=Math.max(1,l.clientHeight-96),w=Math.min(4,Math.max(.1,Math.min(m/i.width,g/i.height)));j(l.clientWidth/2-(i.x+i.width/2)*w,l.clientHeight/2-(i.y+i.height/2)*w,w)},[e,o,n]),v=I.useCallback(l=>{const p=e.current,i=Q[l];if(!p||i===null){L(null,null),j(0,0,1);return}L(i.width,i.height);const m=Math.min(1,Math.max(.1,Math.min((p.clientWidth-96)/i.width,(p.clientHeight-96)/i.height)));j((p.clientWidth-i.width*m)/2,(p.clientHeight-i.height*m)/2,m)},[e]);if(o?.kind!=="react"||!o.adapter.rects)return null;const C=Object.entries(Q).find(([,l])=>l===null?a.width===null:l.width===a.width&&l.height===a.height)?.[0]??"fill";return h.jsxs(h.Fragment,{children:[a.width!==null&&a.height!==null&&h.jsx("div",{"data-testid":"react-canvas-device-frame",style:{position:"absolute",left:0,top:0,zIndex:0,width:a.width,height:a.height,transform:ee(r),transformOrigin:"0 0",pointerEvents:"none",background:"#fff",boxShadow:"0 0 0 1px #ffffff40, 0 8px 30px #0009"}}),h.jsxs(Pe,{label:"React canvas view","data-testid":"react-canvas-zoom-controls",className:"vgai-react-canvas-controls",children:[h.jsxs(Me,{"aria-label":"Responsive viewport",title:"Responsive viewport",value:C,onChange:l=>v(l.target.value),className:"vgai-react-viewport-select",children:[h.jsx("option",{value:"fill",children:"Fill"}),h.jsx("option",{value:"desktop",children:"Desktop · 1440×900"}),h.jsx("option",{value:"tablet",children:"Tablet · 768×1024"}),h.jsx("option",{value:"mobile",children:"Mobile · 390×844"})]}),h.jsx(V,{"aria-label":"Zoom out",title:"Zoom out",size:"comfortable",onClick:()=>s(r.zoom/1.2),children:h.jsx(F,{icon:$e,size:"md"})}),h.jsxs(Re,{variant:"ghost","aria-label":"Reset zoom to 100%",title:"Reset zoom to 100%",size:"comfortable",onClick:()=>s(1),children:[Math.round(r.zoom*100),"%"]}),h.jsx(V,{"aria-label":"Zoom in",title:"Zoom in",size:"comfortable",onClick:()=>s(r.zoom*1.2),children:h.jsx(F,{icon:ze,size:"md"})}),h.jsx(V,{"aria-label":"Zoom to selection",title:"Zoom to selection",size:"comfortable",onClick:f,children:h.jsx(F,{icon:We,size:"md"})})]})]})}function ot(e){return`workspace:world:${e}`}function rt({active:e,composite:o,descriptor:n,store:r}){const a=I.useRef(null),s=I.useRef(null);I.useSyncExternalStore(r.subscribe,r.getSnapshot),I.useEffect(()=>{!e||s.current||!a.current||(s.current=et(a.current,o,r,[n]))},[e,o,n,r]),I.useEffect(()=>()=>{s.current?.(),s.current=null},[]);const f=Oe(Te(r),r.selectedEntityIds),v=f?.worldId===n.worldId?f:null;return h.jsxs("div",{ref:a,"data-testid":`world-document:${n.worldId}`,style:{position:"absolute",inset:0,overflow:"hidden",pointerEvents:"auto",backgroundColor:z.surface.raised,backgroundImage:`linear-gradient(45deg, ${z.surface.chrome} 25%, transparent 25%, transparent 75%, ${z.surface.chrome} 75%), linear-gradient(45deg, ${z.surface.chrome} 25%, transparent 25%, transparent 75%, ${z.surface.chrome} 75%)`,backgroundPosition:"0 0, 8px 8px",backgroundSize:"16px 16px"},children:[h.jsx(Be,{}),h.jsx(tt,{containerRef:a,context:v})]})}function at(e,o){const n=je(),r=[],a=[];for(const s of o.childAdapters())s.role==="world"&&s.kind==="threejs"&&a.push(K(s.worldId,X));for(const s of Ze(o)){const f=ot(s.worldId);a.push(K(s.worldId,f)),r.push(f);const v=C=>h.jsx(rt,{...C,composite:o,descriptor:s,store:e});De({id:f,title:s.worldId,kind:"world",provenance:{rootId:s.worldId,...s.path?{sourcePath:s.path}:{}},Content:v,closeable:!1,onActivate:()=>e.setActiveViewportTab("scene")})}return n?q(n):q(X),()=>{for(const s of a)s();for(const s of r)Ae(s,{discardDirty:!0})}}export{at as installWorldDocuments,ot as worldDocumentId};
|
package/dist/index.html
CHANGED
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
static <style> block keeps only the pre-paint shell layout that must
|
|
26
26
|
be present before any script runs. */
|
|
27
27
|
</style>
|
|
28
|
-
<script type="module" crossorigin src="/assets/index-
|
|
29
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
28
|
+
<script type="module" crossorigin src="/assets/index-8A4JLNIp.js"></script>
|
|
29
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DiUacMXR.css">
|
|
30
30
|
</head>
|
|
31
31
|
<body>
|
|
32
32
|
<div id="editor-chrome-root">
|