castle-web-cli 0.4.82 → 0.4.84

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.
Files changed (37) hide show
  1. package/dist/agent-failures.d.ts +17 -0
  2. package/dist/agent-failures.js +151 -0
  3. package/dist/agent.d.ts +27 -0
  4. package/dist/agent.js +614 -57
  5. package/dist/ide.js +150 -1
  6. package/dist/native/loop.js +40 -1
  7. package/dist/native/openrouter.d.ts +12 -1
  8. package/dist/native/openrouter.js +45 -2
  9. package/dist/native/types.d.ts +6 -0
  10. package/dist/native/types.js +0 -38
  11. package/dist/openrouter-catalog.d.ts +28 -0
  12. package/dist/openrouter-catalog.js +299 -0
  13. package/dist/shell/assets/index-BOgm5T3W.js +144 -0
  14. package/dist/shell/assets/index-DonnH--m.css +1 -0
  15. package/dist/shell/index.html +2 -2
  16. package/dist/shell/operator.png +0 -0
  17. package/kits/basic-2d/CLAUDE.md +27 -23
  18. package/kits/basic-2d/behaviors/Collider.jsx +24 -30
  19. package/kits/basic-2d/behaviors/Layout.jsx +9 -6
  20. package/kits/basic-2d/behaviors/Sprite.jsx +137 -7
  21. package/kits/basic-2d/blueprints/cauldron.scene +3 -5
  22. package/kits/basic-2d/editors/BlueprintLibrary.jsx +11 -11
  23. package/kits/basic-2d/editors/SceneEditor.jsx +212 -50
  24. package/kits/basic-2d/editors/SelectionOverlay.jsx +73 -54
  25. package/kits/basic-2d/editors/inspectorSheet.js +5 -1
  26. package/kits/basic-2d/engine/ScenePlayer.jsx +98 -7
  27. package/kits/basic-2d/engine/autoInspector.jsx +26 -7
  28. package/kits/basic-2d/engine/blueprint.js +35 -8
  29. package/kits/basic-2d/engine/collider.js +146 -0
  30. package/kits/basic-2d/engine/scene.js +53 -30
  31. package/kits/basic-2d/engine/spriteGeometry.js +32 -0
  32. package/kits/basic-2d/engine/ui.jsx +89 -30
  33. package/kits/basic-2d/engine/ui.module.css +157 -53
  34. package/kits/basic-2d/scenes/main.scene +3 -3
  35. package/package.json +2 -1
  36. package/dist/shell/assets/index-ByhgiJoP.js +0 -141
  37. package/dist/shell/assets/index-D6hM_VlW.css +0 -1
@@ -0,0 +1 @@
1
+ .dv-scrollable{position:relative;overflow:hidden}.dv-scrollable .dv-scrollbar-horizontal{will-change:background-color, transform;backface-visibility:hidden;background-color:#0000;border-radius:2px;height:4px;transition:background-color 1s ease-in-out;position:absolute;bottom:0;left:0;transform:translate(0,0)}.dv-scrollable:hover .dv-scrollbar-horizontal,.dv-scrollable.dv-scrollable-resizing .dv-scrollbar-horizontal,.dv-scrollable.dv-scrollable-scrolling .dv-scrollbar-horizontal{background-color:var(--dv-scrollbar-background-color,#ffffff40)}.dv-svg{fill:currentColor;stroke:currentColor;stroke-width:0;line-height:1;display:inline-block}.dockview-theme-dark{--dv-paneview-active-outline-color:dodgerblue;--dv-tabs-and-actions-container-font-size:13px;--dv-tabs-and-actions-container-height:35px;--dv-drag-over-background-color:#53595d80;--dv-drag-over-border-color:transparent;--dv-tabs-container-scrollbar-color:#888;--dv-icon-hover-background-color:#5a5d5e4f;--dv-floating-box-shadow:8px 8px 8px 0px #53595d80;--dv-overlay-z-index:999;--dv-tab-font-size:inherit;--dv-border-radius:0px;--dv-tab-margin:0;--dv-sash-color:transparent;--dv-active-sash-color:transparent;--dv-active-sash-transition-duration:.1s;--dv-active-sash-transition-delay:.5s;--dv-group-view-background-color:#1e1e1e;--dv-tabs-and-actions-container-background-color:#252526;--dv-activegroup-visiblepanel-tab-background-color:#1e1e1e;--dv-activegroup-hiddenpanel-tab-background-color:#2d2d2d;--dv-inactivegroup-visiblepanel-tab-background-color:#1e1e1e;--dv-inactivegroup-hiddenpanel-tab-background-color:#2d2d2d;--dv-tab-divider-color:#1e1e1e;--dv-activegroup-visiblepanel-tab-color:white;--dv-activegroup-hiddenpanel-tab-color:#969696;--dv-inactivegroup-visiblepanel-tab-color:#8f8f8f;--dv-inactivegroup-hiddenpanel-tab-color:#626262;--dv-separator-border:#444;--dv-paneview-header-border-color:#ccc3}.dockview-theme-dark .dv-drop-target-container .dv-drop-target-anchor.dv-drop-target-anchor-container-changed{opacity:0;transition:none}.dockview-theme-light{--dv-paneview-active-outline-color:dodgerblue;--dv-tabs-and-actions-container-font-size:13px;--dv-tabs-and-actions-container-height:35px;--dv-drag-over-background-color:#53595d80;--dv-drag-over-border-color:transparent;--dv-tabs-container-scrollbar-color:#888;--dv-icon-hover-background-color:#5a5d5e4f;--dv-floating-box-shadow:8px 8px 8px 0px #53595d80;--dv-overlay-z-index:999;--dv-tab-font-size:inherit;--dv-border-radius:0px;--dv-tab-margin:0;--dv-sash-color:transparent;--dv-active-sash-color:transparent;--dv-active-sash-transition-duration:.1s;--dv-active-sash-transition-delay:.5s;--dv-group-view-background-color:white;--dv-tabs-and-actions-container-background-color:#f3f3f3;--dv-activegroup-visiblepanel-tab-background-color:white;--dv-activegroup-hiddenpanel-tab-background-color:#ececec;--dv-inactivegroup-visiblepanel-tab-background-color:white;--dv-inactivegroup-hiddenpanel-tab-background-color:#ececec;--dv-tab-divider-color:white;--dv-activegroup-visiblepanel-tab-color:#333;--dv-activegroup-hiddenpanel-tab-color:#333333b3;--dv-inactivegroup-visiblepanel-tab-color:#333333b3;--dv-inactivegroup-hiddenpanel-tab-color:#33333359;--dv-separator-border:#80808059;--dv-paneview-header-border-color:#333;--dv-scrollbar-background-color:#00000040}.dockview-theme-light .dv-drop-target-container .dv-drop-target-anchor.dv-drop-target-anchor-container-changed{opacity:0;transition:none}.dockview-theme-vs{--dv-paneview-active-outline-color:dodgerblue;--dv-tabs-and-actions-container-font-size:11px;--dv-tabs-and-actions-container-height:20px;--dv-drag-over-background-color:#53595d80;--dv-drag-over-border-color:transparent;--dv-tabs-container-scrollbar-color:#888;--dv-icon-hover-background-color:#5a5d5e4f;--dv-floating-box-shadow:8px 8px 8px 0px #53595d80;--dv-overlay-z-index:999;--dv-tab-font-size:inherit;--dv-border-radius:0px;--dv-tab-margin:0;--dv-sash-color:transparent;--dv-active-sash-color:transparent;--dv-active-sash-transition-duration:.1s;--dv-active-sash-transition-delay:.5s;--dv-group-view-background-color:#1e1e1e;--dv-tabs-and-actions-container-background-color:#2d2d30;--dv-activegroup-visiblepanel-tab-background-color:#007acc;--dv-activegroup-hiddenpanel-tab-background-color:#2d2d2d;--dv-inactivegroup-visiblepanel-tab-background-color:#3f3f46;--dv-inactivegroup-hiddenpanel-tab-background-color:#2d2d2d;--dv-tab-divider-color:#1e1e1e;--dv-activegroup-visiblepanel-tab-color:white;--dv-activegroup-hiddenpanel-tab-color:white;--dv-inactivegroup-visiblepanel-tab-color:white;--dv-inactivegroup-hiddenpanel-tab-color:white;--dv-separator-border:#444;--dv-paneview-header-border-color:#ccc3}.dockview-theme-vs .dv-drop-target-container .dv-drop-target-anchor.dv-drop-target-anchor-container-changed{opacity:0;transition:none}.dockview-theme-vs .dv-groupview.dv-active-group>.dv-tabs-and-actions-container{box-sizing:content-box;border-bottom:2px solid var(--dv-activegroup-visiblepanel-tab-background-color)}.dockview-theme-vs .dv-groupview.dv-active-group>.dv-tabs-and-actions-container .dv-tab.dv-active-tab{border-top:2px solid var(--dv-activegroup-visiblepanel-tab-background-color)}.dockview-theme-vs .dv-groupview.dv-active-group>.dv-tabs-and-actions-container .dv-tab.dv-inactive-tab{border-top:2px solid var(--dv-activegroup-hiddenpanel-tab-background-color)}.dockview-theme-vs .dv-groupview.dv-inactive-group>.dv-tabs-and-actions-container{box-sizing:content-box;border-bottom:2px solid var(--dv-inactivegroup-visiblepanel-tab-background-color)}.dockview-theme-vs .dv-groupview.dv-inactive-group>.dv-tabs-and-actions-container .dv-tab.dv-active-tab{border-top:2px solid var(--dv-inactivegroup-visiblepanel-tab-background-color)}.dockview-theme-vs .dv-groupview.dv-inactive-group>.dv-tabs-and-actions-container .dv-tab.dv-inactive-tab{border-top:2px solid var(--dv-inactivegroup-hiddenpanel-tab-background-color)}.dockview-theme-abyss{--dv-paneview-active-outline-color:#596f99;--dv-tabs-and-actions-container-font-size:13px;--dv-tabs-and-actions-container-height:35px;--dv-drag-over-background-color:#53595d80;--dv-drag-over-border-color:transparent;--dv-tabs-container-scrollbar-color:#888;--dv-icon-hover-background-color:#5a5d5e4f;--dv-floating-box-shadow:8px 8px 8px 0px #53595d80;--dv-overlay-z-index:999;--dv-tab-font-size:inherit;--dv-border-radius:0px;--dv-tab-margin:0;--dv-sash-color:transparent;--dv-active-sash-color:transparent;--dv-active-sash-transition-duration:.1s;--dv-active-sash-transition-delay:.5s;--dv-color-abyss-dark:#000c18;--dv-color-abyss:#10192c;--dv-color-abyss-light:#1c1c2a;--dv-color-abyss-lighter:#2b2b4a;--dv-color-abyss-accent:#5b1ecf;--dv-color-abyss-primary-text:white;--dv-color-abyss-secondary-text:#9497a9;--dv-group-view-background-color:var(--dv-color-abyss-dark);--dv-tabs-and-actions-container-background-color:var(--dv-color-abyss-light);--dv-activegroup-visiblepanel-tab-background-color:var(--dv-color-abyss-dark);--dv-activegroup-hiddenpanel-tab-background-color:var(--dv-color-abyss);--dv-inactivegroup-visiblepanel-tab-background-color:var(--dv-color-abyss-dark);--dv-inactivegroup-hiddenpanel-tab-background-color:var(--dv-color-abyss);--dv-tab-divider-color:var(--dv-color-abyss-lighter);--dv-activegroup-visiblepanel-tab-color:white;--dv-activegroup-hiddenpanel-tab-color:#ffffff80;--dv-inactivegroup-visiblepanel-tab-color:#ffffff80;--dv-inactivegroup-hiddenpanel-tab-color:#ffffff40;--dv-separator-border:var(--dv-color-abyss-lighter);--dv-paneview-header-border-color:var(--dv-color-abyss-lighter)}.dockview-theme-abyss .dv-drop-target-container .dv-drop-target-anchor.dv-drop-target-anchor-container-changed{opacity:0;transition:none}.dockview-theme-dracula{--dv-paneview-active-outline-color:#6272a4;--dv-tabs-and-actions-container-font-size:13px;--dv-tabs-and-actions-container-height:35px;--dv-drag-over-background-color:#53595d80;--dv-drag-over-border-color:transparent;--dv-tabs-container-scrollbar-color:#888;--dv-icon-hover-background-color:#5a5d5e4f;--dv-floating-box-shadow:8px 8px 8px 0px #53595d80;--dv-overlay-z-index:999;--dv-tab-font-size:inherit;--dv-border-radius:0px;--dv-tab-margin:0;--dv-sash-color:transparent;--dv-active-sash-color:transparent;--dv-active-sash-transition-duration:.1s;--dv-active-sash-transition-delay:.5s;--dv-group-view-background-color:#282a36;--dv-tabs-and-actions-container-background-color:#191a21;--dv-activegroup-visiblepanel-tab-background-color:#282a36;--dv-activegroup-hiddenpanel-tab-background-color:#21222c;--dv-inactivegroup-visiblepanel-tab-background-color:#282a36;--dv-inactivegroup-hiddenpanel-tab-background-color:#21222c;--dv-tab-divider-color:#191a21;--dv-activegroup-visiblepanel-tab-color:#f8f8f2;--dv-activegroup-hiddenpanel-tab-color:#6272a4;--dv-inactivegroup-visiblepanel-tab-color:#f8f8f280;--dv-inactivegroup-hiddenpanel-tab-color:#6272a480;--dv-separator-border:#bd93f9;--dv-paneview-header-border-color:#bd93f9}.dockview-theme-dracula .dv-drop-target-container .dv-drop-target-anchor.dv-drop-target-anchor-container-changed{opacity:0;transition:none}.dockview-theme-dracula .dv-groupview.dv-active-group>.dv-tabs-and-actions-container .dv-tabs-container>.dv-tab.dv-active-tab{position:relative}.dockview-theme-dracula .dv-groupview.dv-active-group>.dv-tabs-and-actions-container .dv-tabs-container>.dv-tab.dv-active-tab:after{content:"";z-index:999;background-color:#94527e;width:100%;height:1px;position:absolute;top:0;left:0}.dockview-theme-dracula .dv-groupview.dv-inactive-group>.dv-tabs-and-actions-container .dv-tabs-container>.dv-tab.dv-active-tab{position:relative}.dockview-theme-dracula .dv-groupview.dv-inactive-group>.dv-tabs-and-actions-container .dv-tabs-container>.dv-tab.dv-active-tab:after{content:"";z-index:999;background-color:#5e3d5a;width:100%;height:1px;position:absolute;bottom:0;left:0}.dockview-theme-replit{--dv-paneview-active-outline-color:dodgerblue;--dv-tabs-and-actions-container-font-size:13px;--dv-tabs-and-actions-container-height:35px;--dv-drag-over-background-color:#53595d80;--dv-drag-over-border-color:transparent;--dv-tabs-container-scrollbar-color:#888;--dv-icon-hover-background-color:#5a5d5e4f;--dv-floating-box-shadow:8px 8px 8px 0px #53595d80;--dv-overlay-z-index:999;--dv-tab-font-size:inherit;--dv-border-radius:0px;--dv-tab-margin:0;--dv-sash-color:#cfd1d3;--dv-active-sash-color:#babbbb;--dv-active-sash-transition-duration:.1s;--dv-active-sash-transition-delay:.5s;box-sizing:border-box;--dv-group-view-background-color:#ebeced;--dv-tabs-and-actions-container-background-color:#fcfcfc;--dv-activegroup-visiblepanel-tab-background-color:#f0f1f2;--dv-activegroup-hiddenpanel-tab-background-color:#fcfcfc;--dv-inactivegroup-visiblepanel-tab-background-color:#f0f1f2;--dv-inactivegroup-hiddenpanel-tab-background-color:#fcfcfc;--dv-tab-divider-color:transparent;--dv-activegroup-visiblepanel-tab-color:#333;--dv-activegroup-hiddenpanel-tab-color:#333;--dv-inactivegroup-visiblepanel-tab-color:#333;--dv-inactivegroup-hiddenpanel-tab-color:#333;--dv-separator-border:transparent;--dv-paneview-header-border-color:#333;background-color:#ebeced;padding:10px}.dockview-theme-replit .dv-drop-target-container .dv-drop-target-anchor.dv-drop-target-anchor-container-changed{opacity:0;transition:none}.dockview-theme-replit .dv-resize-container:has(>.dv-groupview){border-radius:8px}.dockview-theme-replit .dv-resize-container{border:none;border-radius:10px!important}.dockview-theme-replit .dv-groupview{border-radius:10px;overflow:hidden}.dockview-theme-replit .dv-groupview .dv-tabs-and-actions-container{border-bottom:1px solid #80808059}.dockview-theme-replit .dv-groupview .dv-tabs-and-actions-container .dv-tab{border-radius:8px;margin:4px}.dockview-theme-replit .dv-groupview .dv-tabs-and-actions-container .dv-tab .dv-svg{width:8px;height:8px}.dockview-theme-replit .dv-groupview .dv-tabs-and-actions-container .dv-tab:hover{background-color:#e4e5e6!important}.dockview-theme-replit .dv-groupview .dv-content-container{background-color:#fcfcfc}.dockview-theme-replit .dv-groupview.dv-active-group{border:1px solid #80808059}.dockview-theme-replit .dv-groupview.dv-inactive-group{border:1px solid #0000}.dockview-theme-replit .dv-vertical>.dv-sash-container>.dv-sash{background-color:#0000}.dockview-theme-replit .dv-vertical>.dv-sash-container>.dv-sash:not(.disabled):after{content:"";background-color:var(--dv-sash-color);border-radius:2px;width:40px;height:4px;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.dockview-theme-replit .dv-vertical>.dv-sash-container>.dv-sash:not(.disabled):hover,.dockview-theme-replit .dv-vertical>.dv-sash-container>.dv-sash:not(.disabled):active{background-color:#0000}.dockview-theme-replit .dv-vertical>.dv-sash-container>.dv-sash:not(.disabled):hover:after,.dockview-theme-replit .dv-vertical>.dv-sash-container>.dv-sash:not(.disabled):active:after{background-color:var(--dv-active-sash-color)}.dockview-theme-replit .dv-horizontal>.dv-sash-container>.dv-sash{background-color:#0000}.dockview-theme-replit .dv-horizontal>.dv-sash-container>.dv-sash:not(.disabled):after{content:"";background-color:var(--dv-sash-color);border-radius:2px;width:4px;height:40px;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.dockview-theme-replit .dv-horizontal>.dv-sash-container>.dv-sash:not(.disabled):hover,.dockview-theme-replit .dv-horizontal>.dv-sash-container>.dv-sash:not(.disabled):active{background-color:#0000}.dockview-theme-replit .dv-horizontal>.dv-sash-container>.dv-sash:not(.disabled):hover:after,.dockview-theme-replit .dv-horizontal>.dv-sash-container>.dv-sash:not(.disabled):active:after{background-color:var(--dv-active-sash-color)}.dockview-theme-abyss-spaced{--dv-paneview-active-outline-color:dodgerblue;--dv-tabs-and-actions-container-font-size:13px;--dv-tabs-and-actions-container-height:44px;--dv-drag-over-background-color:"";--dv-drag-over-border-color:transparent;--dv-tabs-container-scrollbar-color:#888;--dv-icon-hover-background-color:#5a5d5e4f;--dv-floating-box-shadow:8px 8px 8px 0px #00000080;--dv-overlay-z-index:999;--dv-tab-font-size:12px;--dv-border-radius:20px;--dv-tab-margin:.5rem .25rem;--dv-sash-color:transparent;--dv-active-sash-color:var(--dv-color-abyss-accent);--dv-active-sash-transition-duration:.1s;--dv-active-sash-transition-delay:.5s;box-sizing:border-box;--dv-color-abyss-dark:#0b0611;--dv-color-abyss:#16121f;--dv-color-abyss-light:#201d2b;--dv-color-abyss-lighter:#2a2837;--dv-color-abyss-accent:#5b1ecf;--dv-color-abyss-primary-text:white;--dv-color-abyss-secondary-text:#9497a9;--dv-drag-over-border:2px solid var(--dv-color-abyss-accent);--dv-group-view-background-color:var(--dv-color-abyss-dark);--dv-tabs-and-actions-container-background-color:var(--dv-color-abyss);--dv-activegroup-visiblepanel-tab-background-color:var(--dv-color-abyss-lighter);--dv-activegroup-hiddenpanel-tab-background-color:var(--dv-color-abyss-light);--dv-inactivegroup-visiblepanel-tab-background-color:var(--dv-color-abyss-lighter);--dv-inactivegroup-hiddenpanel-tab-background-color:var(--dv-color-abyss-light);--dv-tab-divider-color:transparent;--dv-activegroup-visiblepanel-tab-color:var(--dv-color-abyss-primary-text);--dv-activegroup-hiddenpanel-tab-color:var(--dv-color-abyss-secondary-text);--dv-inactivegroup-visiblepanel-tab-color:var(--dv-color-abyss-primary-text);--dv-inactivegroup-hiddenpanel-tab-color:var(--dv-color-abyss-secondary-text);--dv-separator-border:transparent;--dv-paneview-header-border-color:#333;background-color:var(--dv-color-abyss-dark);padding:10px}.dockview-theme-abyss-spaced .dv-resize-container:has(>.dv-groupview){border-radius:8px}.dockview-theme-abyss-spaced .dv-sash{border-radius:4px}.dockview-theme-abyss-spaced .dv-drop-target-anchor{border-radius:calc(var(--dv-border-radius) / 4)}.dockview-theme-abyss-spaced .dv-drop-target-anchor.dv-drop-target-content{border-radius:var(--dv-border-radius)}.dockview-theme-abyss-spaced .dv-resize-container{border:none;border-radius:var(--dv-border-radius)!important}.dockview-theme-abyss-spaced .dv-tabs-overflow-container,.dockview-theme-abyss-spaced .dv-tabs-overflow-dropdown-default{border-radius:8px;height:unset!important}.dockview-theme-abyss-spaced .dv-tab{border-radius:8px}.dockview-theme-abyss-spaced .dv-tab .dv-svg{width:8px;height:8px}.dockview-theme-abyss-spaced .dv-groupview{border-radius:var(--dv-border-radius)}.dockview-theme-abyss-spaced .dv-groupview .dv-tabs-and-actions-container{padding:0px calc(var(--dv-border-radius) / 2)}.dockview-theme-abyss-spaced .dv-groupview .dv-content-container{background-color:var(--dv-tabs-and-actions-container-background-color)}.dockview-theme-abyss-spaced .dv-resize-container .dv-groupview{border:2px solid var(--dv-color-abyss-dark)}.dockview-theme-light-spaced{--dv-paneview-active-outline-color:dodgerblue;--dv-tabs-and-actions-container-font-size:13px;--dv-tabs-and-actions-container-height:44px;--dv-drag-over-background-color:"";--dv-drag-over-border-color:transparent;--dv-tabs-container-scrollbar-color:#888;--dv-icon-hover-background-color:#5a5d5e4f;--dv-floating-box-shadow:8px 8px 8px 0px #0000001a;--dv-overlay-z-index:999;--dv-tab-font-size:12px;--dv-border-radius:20px;--dv-tab-margin:.5rem .25rem;--dv-sash-color:transparent;--dv-active-sash-color:#5b1ecf;--dv-active-sash-transition-duration:.1s;--dv-active-sash-transition-delay:.5s;box-sizing:border-box;--dv-drag-over-border:2px solid #5b1ecf;--dv-group-view-background-color:#f6f5f9;--dv-tabs-and-actions-container-background-color:white;--dv-activegroup-visiblepanel-tab-background-color:#ededf0;--dv-activegroup-hiddenpanel-tab-background-color:#f9f9fa;--dv-inactivegroup-visiblepanel-tab-background-color:#ededf0;--dv-inactivegroup-hiddenpanel-tab-background-color:#f9f9fa;--dv-tab-divider-color:transparent;--dv-activegroup-visiblepanel-tab-color:#686b82;--dv-activegroup-hiddenpanel-tab-color:#9497a9;--dv-inactivegroup-visiblepanel-tab-color:#686b82;--dv-inactivegroup-hiddenpanel-tab-color:#9497a9;--dv-separator-border:transparent;--dv-paneview-header-border-color:#333;--dv-scrollbar-background-color:#00000040;background-color:#f6f5f9;padding:10px}.dockview-theme-light-spaced .dv-resize-container:has(>.dv-groupview){border-radius:8px}.dockview-theme-light-spaced .dv-sash{border-radius:4px}.dockview-theme-light-spaced .dv-drop-target-anchor{border-radius:calc(var(--dv-border-radius) / 4)}.dockview-theme-light-spaced .dv-drop-target-anchor.dv-drop-target-content{border-radius:var(--dv-border-radius)}.dockview-theme-light-spaced .dv-resize-container{border:none;border-radius:var(--dv-border-radius)!important}.dockview-theme-light-spaced .dv-tabs-overflow-container,.dockview-theme-light-spaced .dv-tabs-overflow-dropdown-default{border-radius:8px;height:unset!important}.dockview-theme-light-spaced .dv-tab{border-radius:8px}.dockview-theme-light-spaced .dv-tab .dv-svg{width:8px;height:8px}.dockview-theme-light-spaced .dv-groupview{border-radius:var(--dv-border-radius)}.dockview-theme-light-spaced .dv-groupview .dv-tabs-and-actions-container{padding:0px calc(var(--dv-border-radius) / 2)}.dockview-theme-light-spaced .dv-groupview .dv-content-container{background-color:var(--dv-tabs-and-actions-container-background-color)}.dockview-theme-light-spaced .dv-resize-container .dv-groupview{border:2px solid #ffffff1a}.dv-drop-target-container{z-index:9999;pointer-events:none;--dv-transition-duration:.3s;width:100%;height:100%;position:absolute;top:0;left:0;overflow:hidden}.dv-drop-target-container .dv-drop-target-anchor{border:var(--dv-drag-over-border);background-color:var(--dv-drag-over-background-color);opacity:1;will-change:transform, opacity;backface-visibility:hidden;contain:layout paint;transition:opacity var(--dv-transition-duration) ease-in, transform var(--dv-transition-duration) ease-out;position:relative;transform:translate(0,0)}.dv-drop-target{--dv-transition-duration:70ms;position:relative}.dv-drop-target>.dv-drop-target-dropzone{z-index:1000;pointer-events:none;width:100%;height:100%;position:absolute;top:0;left:0}.dv-drop-target>.dv-drop-target-dropzone>.dv-drop-target-selection{box-sizing:border-box;border:var(--dv-drag-over-border);background-color:var(--dv-drag-over-background-color);width:100%;height:100%;transition:top var(--dv-transition-duration) ease-out, left var(--dv-transition-duration) ease-out, width var(--dv-transition-duration) ease-out, height var(--dv-transition-duration) ease-out, opacity var(--dv-transition-duration) ease-out;will-change:transform;pointer-events:none;position:relative}.dv-drop-target>.dv-drop-target-dropzone>.dv-drop-target-selection.dv-drop-target-top.dv-drop-target-small-vertical{border-top:1px solid var(--dv-drag-over-border-color)}.dv-drop-target>.dv-drop-target-dropzone>.dv-drop-target-selection.dv-drop-target-bottom.dv-drop-target-small-vertical{border-bottom:1px solid var(--dv-drag-over-border-color)}.dv-drop-target>.dv-drop-target-dropzone>.dv-drop-target-selection.dv-drop-target-left.dv-drop-target-small-horizontal{border-left:1px solid var(--dv-drag-over-border-color)}.dv-drop-target>.dv-drop-target-dropzone>.dv-drop-target-selection.dv-drop-target-right.dv-drop-target-small-horizontal{border-right:1px solid var(--dv-drag-over-border-color)}.dv-dockview{background-color:var(--dv-group-view-background-color);contain:layout;position:relative}.dv-dockview .dv-watermark-container{z-index:1;width:100%;height:100%;position:absolute;top:0;left:0}.dv-dockview .dv-overlay-render-container{position:relative}.dv-groupview.dv-active-group>.dv-tabs-and-actions-container .dv-tabs-container>.dv-tab.dv-active-tab{background-color:var(--dv-activegroup-visiblepanel-tab-background-color);color:var(--dv-activegroup-visiblepanel-tab-color)}.dv-groupview.dv-active-group>.dv-tabs-and-actions-container .dv-tabs-container>.dv-tab.dv-inactive-tab{background-color:var(--dv-activegroup-hiddenpanel-tab-background-color);color:var(--dv-activegroup-hiddenpanel-tab-color)}.dv-groupview.dv-inactive-group>.dv-tabs-and-actions-container .dv-tabs-container>.dv-tab.dv-active-tab{background-color:var(--dv-inactivegroup-visiblepanel-tab-background-color);color:var(--dv-inactivegroup-visiblepanel-tab-color)}.dv-groupview.dv-inactive-group>.dv-tabs-and-actions-container .dv-tabs-container>.dv-tab.dv-inactive-tab{background-color:var(--dv-inactivegroup-hiddenpanel-tab-background-color);color:var(--dv-inactivegroup-hiddenpanel-tab-color)}.dv-tab.dv-tab-dragging{background-color:var(--dv-activegroup-visiblepanel-tab-background-color);color:var(--dv-activegroup-visiblepanel-tab-color)}.dv-groupview{background-color:var(--dv-group-view-background-color);flex-direction:column;height:100%;display:flex;overflow:hidden}.dv-groupview:focus{outline:none}.dv-groupview>.dv-content-container{outline:none;flex-grow:1;min-height:0}.dv-root-wrapper,.dv-grid-view,.dv-branch-node{width:100%;height:100%}.dv-debug .dv-resize-container .dv-resize-handle-top{background-color:red}.dv-debug .dv-resize-container .dv-resize-handle-bottom{background-color:green}.dv-debug .dv-resize-container .dv-resize-handle-left{background-color:#ff0}.dv-debug .dv-resize-container .dv-resize-handle-right{background-color:#00f}.dv-debug .dv-resize-container .dv-resize-handle-topleft,.dv-debug .dv-resize-container .dv-resize-handle-topright,.dv-debug .dv-resize-container .dv-resize-handle-bottomleft,.dv-debug .dv-resize-container .dv-resize-handle-bottomright{background-color:#0ff}.dv-resize-container{--dv-overlay-z-index:var(--dv-overlay-z-index,999);z-index:calc(var(--dv-overlay-z-index) - 2);border:1px solid var(--dv-tab-divider-color);box-shadow:var(--dv-floating-box-shadow);will-change:transform, opacity;backface-visibility:hidden;position:absolute;transform:translate(0,0)}.dv-resize-container.dv-hidden{display:none}.dv-resize-container.dv-resize-container-dragging{opacity:.5;will-change:transform, opacity}.dv-resize-container .dv-resize-handle-top{width:calc(100% - 8px);height:4px;z-index:var(--dv-overlay-z-index);cursor:ns-resize;position:absolute;top:-2px;left:4px}.dv-resize-container .dv-resize-handle-bottom{width:calc(100% - 8px);height:4px;z-index:var(--dv-overlay-z-index);cursor:ns-resize;position:absolute;bottom:-2px;left:4px}.dv-resize-container .dv-resize-handle-left{width:4px;height:calc(100% - 8px);z-index:var(--dv-overlay-z-index);cursor:ew-resize;position:absolute;top:4px;left:-2px}.dv-resize-container .dv-resize-handle-right{width:4px;height:calc(100% - 8px);z-index:var(--dv-overlay-z-index);cursor:ew-resize;position:absolute;top:4px;right:-2px}.dv-resize-container .dv-resize-handle-topleft{width:4px;height:4px;z-index:var(--dv-overlay-z-index);cursor:nw-resize;position:absolute;top:-2px;left:-2px}.dv-resize-container .dv-resize-handle-topright{width:4px;height:4px;z-index:var(--dv-overlay-z-index);cursor:ne-resize;position:absolute;top:-2px;right:-2px}.dv-resize-container .dv-resize-handle-bottomleft{width:4px;height:4px;z-index:var(--dv-overlay-z-index);cursor:sw-resize;position:absolute;bottom:-2px;left:-2px}.dv-resize-container .dv-resize-handle-bottomright{width:4px;height:4px;z-index:var(--dv-overlay-z-index);cursor:se-resize;position:absolute;bottom:-2px;right:-2px}.dv-render-overlay{--dv-overlay-z-index:var(--dv-overlay-z-index,999);z-index:1;contain:layout paint;isolation:isolate;will-change:transform;backface-visibility:hidden;width:100%;height:100%;position:absolute;transform:translate(0,0)}.dv-render-overlay.dv-render-overlay-float{z-index:calc(var(--dv-overlay-z-index) - 1)}.dv-debug .dv-render-overlay{outline-offset:-1;outline:1px solid red}.dv-pane-container{width:100%;height:100%}.dv-pane-container.dv-animated .dv-view{will-change:transform;backface-visibility:hidden;transition:transform .15s ease-out;transform:translate(0,0)}.dv-pane-container .dv-view{flex-direction:column;display:flex;overflow:hidden;padding:0!important}.dv-pane-container .dv-view:not(:first-child):before{background-color:#0000!important}.dv-pane-container .dv-view:not(:first-child) .dv-pane>.dv-pane-header{border-top:1px solid var(--dv-paneview-header-border-color)}.dv-pane-container .dv-view .dv-default-header{background-color:var(--dv-group-view-background-color);color:var(--dv-activegroup-visiblepanel-tab-color);cursor:pointer;padding:0 8px;display:flex}.dv-pane-container .dv-view .dv-default-header .dv-pane-header-icon{justify-content:center;align-items:center;display:flex}.dv-pane-container .dv-view .dv-default-header>span{flex-grow:1;padding-left:8px}.dv-pane-container:first-of-type>.dv-pane>.dv-pane-header{border-top:none!important}.dv-pane-container .dv-pane{flex-direction:column;height:100%;display:flex;overflow:hidden}.dv-pane-container .dv-pane .dv-pane-header{box-sizing:border-box;-webkit-user-select:none;user-select:none;outline:none;position:relative}.dv-pane-container .dv-pane .dv-pane-header.dv-pane-draggable{cursor:pointer}.dv-pane-container .dv-pane .dv-pane-header:focus:before,.dv-pane-container .dv-pane .dv-pane-header:focus-within:before{z-index:5;content:"";pointer-events:none;outline-offset:-1px;outline:-1px solid;outline-color:var(--dv-paneview-active-outline-color);width:100%;height:100%;position:absolute;top:0;left:0}.dv-pane-container .dv-pane .dv-pane-body{outline:none;flex-grow:1;position:relative;overflow:hidden auto}.dv-pane-container .dv-pane .dv-pane-body:focus:before,.dv-pane-container .dv-pane .dv-pane-body:focus-within:before{z-index:5;content:"";pointer-events:none;outline-offset:-1px;outline:-1px solid;outline-color:var(--dv-paneview-active-outline-color);width:100%;height:100%;position:absolute;top:0;left:0}.dv-debug .dv-split-view-container .dv-sash-container .dv-sash.dv-enabled{background-color:#000}.dv-debug .dv-split-view-container .dv-sash-container .dv-sash.dv-disabled{background-color:orange}.dv-debug .dv-split-view-container .dv-sash-container .dv-sash.dv-maximum{background-color:green}.dv-debug .dv-split-view-container .dv-sash-container .dv-sash.dv-minimum{background-color:red}.dv-split-view-container{width:100%;height:100%;position:relative;overflow:hidden}.dv-split-view-container.dv-splitview-disabled>.dv-sash-container>.dv-sash{pointer-events:none}.dv-split-view-container.dv-animation .dv-view,.dv-split-view-container.dv-animation .dv-sash{will-change:transform;backface-visibility:hidden;transition:transform .15s ease-out;transform:translate(0,0)}.dv-split-view-container.dv-horizontal{height:100%}.dv-split-view-container.dv-horizontal>.dv-sash-container>.dv-sash{width:4px;height:100%}.dv-split-view-container.dv-horizontal>.dv-sash-container>.dv-sash.dv-enabled{cursor:ew-resize}.dv-split-view-container.dv-horizontal>.dv-sash-container>.dv-sash.dv-disabled{cursor:default}.dv-split-view-container.dv-horizontal>.dv-sash-container>.dv-sash.dv-maximum{cursor:w-resize}.dv-split-view-container.dv-horizontal>.dv-sash-container>.dv-sash.dv-minimum{cursor:e-resize}.dv-split-view-container.dv-horizontal>.dv-view-container>.dv-view:not(:first-child):before{width:1px;height:100%}.dv-split-view-container.dv-vertical{width:100%}.dv-split-view-container.dv-vertical>.dv-sash-container>.dv-sash{width:100%;height:4px}.dv-split-view-container.dv-vertical>.dv-sash-container>.dv-sash.dv-enabled{cursor:ns-resize}.dv-split-view-container.dv-vertical>.dv-sash-container>.dv-sash.dv-disabled{cursor:default}.dv-split-view-container.dv-vertical>.dv-sash-container>.dv-sash.dv-maximum{cursor:n-resize}.dv-split-view-container.dv-vertical>.dv-sash-container>.dv-sash.dv-minimum{cursor:s-resize}.dv-split-view-container.dv-vertical>.dv-view-container>.dv-view{width:100%}.dv-split-view-container.dv-vertical>.dv-view-container>.dv-view:not(:first-child):before{width:100%;height:1px}.dv-split-view-container .dv-sash-container{width:100%;height:100%;position:absolute}.dv-split-view-container .dv-sash-container .dv-sash{z-index:99;-webkit-user-select:none;user-select:none;touch-action:none;background-color:var(--dv-sash-color,transparent);outline:none;position:absolute}.dv-split-view-container .dv-sash-container .dv-sash:not(.disabled):active,.dv-split-view-container .dv-sash-container .dv-sash:not(.disabled):hover{background-color:var(--dv-active-sash-color,transparent);transition-property:background-color;transition-timing-function:ease-in-out;transition-duration:var(--dv-active-sash-transition-duration,.1s);transition-delay:var(--dv-active-sash-transition-delay,.5s)}.dv-split-view-container .dv-view-container{width:100%;height:100%;position:relative}.dv-split-view-container .dv-view-container .dv-view{box-sizing:border-box;height:100%;position:absolute;overflow:auto}.dv-split-view-container.dv-separator-border .dv-view:not(:first-child):before{content:" ";z-index:5;pointer-events:none;background-color:var(--dv-separator-border);position:absolute;top:0;left:0}.dv-dragged{transform:translate(0,0)}.dv-tab{flex-shrink:0}.dv-tab:focus-within,.dv-tab:focus{position:relative}.dv-tab:focus-within:after,.dv-tab:focus:after{content:"";pointer-events:none;outline-offset:-1px;z-index:5;width:100%;height:100%;position:absolute;top:0;left:0;outline:1px solid var(--dv-tab-divider-color)!important}.dv-tab.dv-tab-dragging .dv-default-tab-action{background-color:var(--dv-activegroup-visiblepanel-tab-color)}.dv-tab.dv-active-tab .dv-default-tab .dv-default-tab-action{visibility:visible}.dv-tab.dv-inactive-tab .dv-default-tab .dv-default-tab-action{visibility:hidden}.dv-tab.dv-inactive-tab .dv-default-tab:hover .dv-default-tab-action{visibility:visible}.dv-tab .dv-default-tab{white-space:nowrap;text-overflow:ellipsis;align-items:center;height:100%;display:flex;position:relative}.dv-tab .dv-default-tab .dv-default-tab-content{flex-grow:1;margin-right:4px}.dv-tab .dv-default-tab .dv-default-tab-action{box-sizing:border-box;justify-content:center;align-items:center;padding:4px;display:flex}.dv-tab .dv-default-tab .dv-default-tab-action:hover{background-color:var(--dv-icon-hover-background-color);border-radius:2px}.dv-tabs-overflow-dropdown-default{height:100%;color:var(--dv-activegroup-hiddenpanel-tab-color);margin:var(--dv-tab-margin);cursor:pointer;flex-shrink:0;align-items:center;padding:.25rem .5rem;display:flex}.dv-tabs-overflow-dropdown-default>span{padding-left:.25rem}.dv-tabs-overflow-dropdown-default>svg{transform:rotate(90deg)}.dv-tabs-container{scrollbar-width:thin;will-change:scroll-position;height:100%;display:flex;overflow:auto;transform:translate(0,0)}.dv-tabs-container.dv-horizontal .dv-tab:not(:first-child):before{content:" ";z-index:5;pointer-events:none;background-color:var(--dv-tab-divider-color);width:1px;height:100%;position:absolute;top:0;left:0}.dv-tabs-container::-webkit-scrollbar{height:3px}.dv-tabs-container::-webkit-scrollbar-track{background:0 0}.dv-tabs-container::-webkit-scrollbar-thumb{background:var(--dv-tabs-container-scrollbar-color)}.dv-scrollable>.dv-tabs-container{overflow:hidden}.dv-tab{-webkit-user-drag:element;cursor:pointer;box-sizing:border-box;font-size:var(--dv-tab-font-size);margin:var(--dv-tab-margin);outline:none;padding:.25rem .5rem;position:relative}.dv-tabs-overflow-container{height:unset;border:1px solid var(--dv-tab-divider-color);background-color:var(--dv-group-view-background-color);flex-direction:column}.dv-tabs-overflow-container .dv-tab:not(:last-child){border-bottom:1px solid var(--dv-tab-divider-color)}.dv-tabs-overflow-container .dv-active-tab{background-color:var(--dv-activegroup-visiblepanel-tab-background-color);color:var(--dv-activegroup-visiblepanel-tab-color)}.dv-tabs-overflow-container .dv-inactive-tab{background-color:var(--dv-activegroup-hiddenpanel-tab-background-color);color:var(--dv-activegroup-hiddenpanel-tab-color)}.dv-tabs-and-actions-container{background-color:var(--dv-tabs-and-actions-container-background-color);box-sizing:border-box;height:var(--dv-tabs-and-actions-container-height);font-size:var(--dv-tabs-and-actions-container-font-size);flex-shrink:0;display:flex}.dv-tabs-and-actions-container.dv-single-tab.dv-full-width-single-tab .dv-scrollable,.dv-tabs-and-actions-container.dv-single-tab.dv-full-width-single-tab .dv-tabs-container{flex-grow:1}.dv-tabs-and-actions-container.dv-single-tab.dv-full-width-single-tab .dv-tabs-container .dv-tab{flex-grow:1;padding:0}.dv-tabs-and-actions-container.dv-single-tab.dv-full-width-single-tab .dv-void-container{flex-grow:0}.dv-tabs-and-actions-container .dv-void-container{flex-grow:1;display:flex}.dv-tabs-and-actions-container .dv-void-container.dv-draggable{cursor:grab}.dv-tabs-and-actions-container .dv-right-actions-container{display:flex}.dv-watermark{height:100%;display:flex}.xterm{cursor:text;-webkit-user-select:none;user-select:none;position:relative}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{z-index:5;position:absolute;top:0}.xterm .xterm-helper-textarea{opacity:0;z-index:-5;white-space:nowrap;resize:none;border:0;width:0;height:0;margin:0;padding:0;position:absolute;top:0;left:-9999em;overflow:hidden}.xterm .composition-view{color:#fff;white-space:nowrap;z-index:1;background:#000;display:none;position:absolute}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{cursor:default;background-color:#000;position:absolute;inset:0;overflow-y:scroll}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;top:0;left:0}.xterm-char-measure-element{visibility:hidden;line-height:normal;display:inline-block;position:absolute;top:0;left:-9999em}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{z-index:10;color:#0000;pointer-events:none;position:absolute;inset:0}.xterm .xterm-accessibility-tree:not(.debug) ::selection{color:#0000}.xterm .xterm-accessibility-tree{-webkit-user-select:text;user-select:text;white-space:pre;font-family:monospace}.xterm .xterm-accessibility-tree>div{transform-origin:0;width:fit-content}.xterm .live-region{width:1px;height:1px;position:absolute;left:-9999px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{-webkit-text-decoration:underline double;text-decoration:underline double}.xterm-underline-3{-webkit-text-decoration:underline wavy;text-decoration:underline wavy}.xterm-underline-4{-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.xterm-underline-5{-webkit-text-decoration:underline dashed;text-decoration:underline dashed}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:underline overline}.xterm-overline.xterm-underline-2{-webkit-text-decoration:overline double underline;text-decoration:overline double underline}.xterm-overline.xterm-underline-3{-webkit-text-decoration:overline wavy underline;text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{-webkit-text-decoration:overline dotted underline;text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{-webkit-text-decoration:overline dashed underline;text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;pointer-events:none;position:absolute;top:0;right:0}.xterm-decoration-top{z-index:2;position:relative}.xterm .xterm-scrollable-element>.scrollbar{cursor:default}.xterm .xterm-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.xterm .xterm-scrollable-element>.visible{opacity:1;z-index:11;background:0 0;transition:opacity .1s linear}.xterm .xterm-scrollable-element>.invisible{opacity:0;pointer-events:none}.xterm .xterm-scrollable-element>.invisible.fade{transition:opacity .8s linear}.xterm .xterm-scrollable-element>.shadow{display:none;position:absolute}.xterm .xterm-scrollable-element>.shadow.top{width:100%;height:3px;box-shadow:var(--vscode-scrollbar-shadow,#000) 0 6px 6px -6px inset;display:block;top:0;left:3px}.xterm .xterm-scrollable-element>.shadow.left{width:3px;height:100%;box-shadow:var(--vscode-scrollbar-shadow,#000) 6px 0 6px -6px inset;display:block;top:3px;left:0}.xterm .xterm-scrollable-element>.shadow.top-left-corner{width:3px;height:3px;display:block;top:0;left:0}.xterm .xterm-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow,#000) 6px 0 6px -6px inset}.castle-file-panel,.castle-code-panel{--castle-font-mono:"SFMono-Regular", Consolas, "Liberation Mono", monospace;--castle-black:var(--v2-ink);--castle-panel-raised:var(--v2-raised);--castle-border:#444;--castle-text:var(--v2-white);--castle-text-dim:var(--v2-muted);--castle-inspector-bg:var(--v2-surface);--castle-inspector-text:var(--v2-fg);--castle-inspector-muted:var(--v2-muted);--castle-inspector-border:var(--v2-border);--castle-inspector-divider:var(--v2-border);--castle-inspector-input-bg:var(--v2-raised);--castle-workspace-bg:var(--v2-surface);--castle-sheet-bg:var(--v2-surface);--castle-radius:4px}.castle-file-panel{background:var(--castle-sheet-bg);flex-direction:column;height:100%;display:flex;overflow:hidden;transform:translateZ(0)}.castle-file-panel>.fileBrowserBare{flex:1 1 0;height:auto;min-height:0}.castle-file-toolbar{border-bottom:1px solid var(--castle-inspector-border);flex:none;align-items:center;gap:6px;padding:6px 8px;display:flex}.castle-file-new-btn{color:#e6e6e6;cursor:pointer;background:#2f2f2f;border:1px solid #4a4a4a;border-radius:4px;align-items:center;gap:6px;padding:4px 10px;font-size:13px;display:inline-flex}.castle-file-new-btn:hover{background:#3c3c3c}.castle-file-new-btn svg{width:12px;height:12px}.castle-file-icon-btn{color:#b0b0b0;cursor:pointer;background:#2f2f2f;border:1px solid #4a4a4a;border-radius:4px;justify-content:center;align-items:center;width:28px;height:26px;margin-left:auto;display:inline-flex}.castle-file-icon-btn:hover{color:#e6e6e6;background:#3c3c3c}.castle-file-icon-btn.active{color:#dbe6f5;background:#37506f;border-color:#4a6b95}.castle-file-icon-btn svg{width:14px;height:14px}.castle-file-action-error{color:#e86a73;background:#2a1414;flex:none;justify-content:space-between;align-items:center;gap:8px;padding:5px 10px;font-size:12px;display:flex}.castle-file-action-error button{color:inherit;cursor:pointer;background:0 0;border:0;font-size:15px;line-height:1}.fileEditRow{cursor:default}.fileEditInput{border:1px solid var(--castle-border);background:var(--castle-inspector-input-bg);min-width:0;color:var(--castle-inspector-text);font:inherit;border-radius:3px;flex:auto;padding:1px 4px;font-size:13px}.fileEditInput:focus{border-color:#5a8bd6;outline:none}.fileEditSuffix{color:var(--castle-text-dim);flex:none;font-size:13px}.fileEditError{padding:2px 0 0 calc(20px + var(--file-depth,0) * 20px);color:#e86a73;flex:1 0 100%;font-size:11px}.castle-file-menu{z-index:1000;background:#232323;border:1px solid #3a3a3a;border-radius:6px;min-width:168px;padding:4px;position:fixed;box-shadow:0 8px 24px #0000008c}.castle-file-menu-item{color:#e6e6e6;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:4px;align-items:center;gap:8px;width:100%;padding:6px 8px;font-size:13px;display:flex}.castle-file-menu-item:hover:not(:disabled){background:#3a3a3a}.castle-file-menu-item:disabled{opacity:.4;cursor:default}.castle-file-menu-item.danger{color:#e86a73}.castle-file-menu-item.danger:hover{background:#3a2222}.castle-file-menu-item-icon{color:#b0b0b0;flex:0 0 14px;justify-content:center;align-items:center;width:14px;display:inline-flex}.castle-file-menu-item.danger .castle-file-menu-item-icon{color:inherit}.castle-file-menu-item-icon svg{width:13px;height:13px}.castle-file-menu-confirm{min-width:180px;padding:6px 8px}.castle-file-menu-confirm-text{color:#e6e6e6;margin-bottom:8px;font-size:13px}.castle-file-menu-confirm-actions{justify-content:flex-end;gap:6px;display:flex}.castle-file-menu-confirm-actions button{color:#e6e6e6;cursor:pointer;background:#333;border:1px solid #4a4a4a;border-radius:4px;padding:4px 10px;font-size:12px}.castle-file-menu-confirm-actions button:hover{background:#404040}.castle-file-menu-confirm-actions button.danger{color:#fff;background:#a02828;border-color:#a02828}.castle-file-menu-confirm-actions button.danger:hover{background:#b83030}.castle-file-menu-item-label{text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:0;overflow:hidden}.castle-file-menu-check{color:#7fd08a;flex:none;font-size:12px}.castle-file-menu-keys{color:gray;white-space:nowrap;flex:none;margin-left:16px;font-family:SFMono-Regular,Consolas,monospace;font-size:11px}.castle-file-menu-item:disabled .castle-file-menu-keys{color:inherit}.castle-file-menu-header{color:#9a9a9a;text-transform:uppercase;letter-spacing:.04em;padding:5px 8px 6px;font-size:11px}.castle-file-menu-sep{background:#3a3a3a;height:1px;margin:4px 2px}.castle-file-menu-error{color:#e86a73;padding:4px 8px;font-size:11px}.castle-file-picker{min-width:180px;max-height:min(60vh,420px);overflow-y:auto}.castle-file-newfolder{align-items:center;gap:6px;padding:4px 6px;display:flex}.castle-file-newfolder .fileEditInput{flex:auto}.castle-file-newfolder-btn{color:#e6e6e6;cursor:pointer;background:#333;border:1px solid #4a4a4a;border-radius:4px;flex:none;padding:3px 10px;font-size:12px}.castle-file-newfolder-btn:hover{background:#404040}.castle-file-newfolder-btn:disabled{opacity:.5;cursor:default}.fileBrowserBare{flex-direction:column;min-width:0;height:100%;display:flex}.fileTree{flex:1 1 0;min-height:0;padding-top:5px;overflow-y:auto}.fileBranch{min-width:0}.fileRow,.fileDirRow{border-radius:var(--castle-radius);width:100%;color:var(--v2-secondary);padding:5px 9px 5px calc(9px + var(--file-depth,0) * 20px);text-align:left;cursor:pointer;background:0 0;border:0;justify-content:flex-start;align-items:center;gap:6px;font-size:14px;display:flex}.fileDirRow{color:var(--v2-muted)}.fileRow:hover,.fileDirRow:hover{background:var(--castle-sheet-bg);color:var(--castle-inspector-text)}.fileRow.fileRowSelected,.fileRow.fileRowSelected:hover{background:var(--castle-panel-raised);color:var(--castle-inspector-text)}.fileIcon.fileDisclosure{color:var(--v2-placeholder)}.fileDirRow:hover .fileIcon.fileDisclosure{color:inherit}.fileDisclosure svg{width:10px;height:10px}.fileLabel{flex:auto;align-items:center;gap:6px;min-width:0;display:inline-flex}.fileIcon{width:14px;color:var(--castle-inspector-muted);flex:0 0 14px;justify-content:center;align-items:center;font-size:14px;display:inline-flex}.castle-code-panel{width:100%;height:100%;position:relative}.mainEditor{background:var(--castle-sheet-bg);flex-direction:column;width:100%;min-width:0;height:100%;min-height:0;display:flex}.editorBody{flex:1;min-height:0;display:flex;overflow:hidden;container:editor/inline-size}.codeEditor{background:var(--castle-workspace-bg);flex:1;grid-template-columns:1fr;min-width:0;min-height:0;display:grid}.codeMirrorHost{min-width:0;height:100%;min-height:0}.castle-code-overlay{color:var(--castle-inspector-muted);pointer-events:none;font-size:12px;position:absolute;top:10px;left:12px}.castle-code-overlay.castle-code-error{color:var(--v2-error)}.castle-code-savebar{background:var(--v2-error-bg);color:var(--v2-error);padding:4px 10px;font-size:11px;position:absolute;bottom:0;left:0;right:0}:root{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark;--v2-gutter:#000;--v2-surface:#0d0d0d;--v2-raised:#161616;--v2-hover:#1d1d1d;--v2-fg:#e6e6e6;--v2-head:#e8e8e8;--v2-secondary:#b3b3b3;--v2-muted:#888;--v2-dim:#525252;--v2-placeholder:#666;--v2-ink:#111;--v2-white:#fff;--v2-border:#2a2a2a;--v2-accent:#622461;--v2-accent-hover:#855484;--v2-running:#6c9ce0;--v2-running-ring:#6c9ce040;--v2-avatar-ring:#fff;--v2-avatar-ring-hover:#b3b3b3;--v2-error-bg:#5a2b2b;--v2-warn:#e2c08d;--v2-error:#e08c8c;--v2-overlay-scrim:#00000059;--v2-overlay-code:#00000038;--v2-overlay-code-block:#00000047;--v2-overlay-task:#141414eb;--v2-overlay-feed-code:#7878784d;--v2-overlay-white-subtle:#ffffff0f;--v2-overlay-white-hover:#ffffff14;--v2-overlay-white-border:#ffffff24;--v2-overlay-white-quote:#fff6;--v2-overlay-white-dim:#ffffffd9;--v2-shadow-pop:0 10px 24px -10px #000000e6;--v2-text-shadow-float:0 1px 3px #000000f2, 0 0 2px #000000d9;--v2-selection:#e6e6e62e;--v2-mono:ui-monospace, SFMono-Regular, Menlo, monospace;--panel-gutter:10px;--panel-chrome-radius:8px}*{box-sizing:border-box}html,body,#root{height:100%;margin:0}body{color:var(--v2-fg);background:var(--v2-surface);font-family:baltomobile,Balto,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;overflow:hidden}.shell-dockview{box-sizing:border-box;--dv-tab-font-size:14px;--dv-tabs-and-actions-container-font-size:14px;--dv-tabs-and-actions-container-height:30px;--dv-group-view-background-color:var(--v2-surface);--dv-tabs-and-actions-container-background-color:var(--v2-gutter);--dv-activegroup-visiblepanel-tab-background-color:var(--v2-surface);--dv-activegroup-visiblepanel-tab-color:var(--v2-fg);--dv-activegroup-hiddenpanel-tab-background-color:var(--v2-gutter);--dv-activegroup-hiddenpanel-tab-color:var(--v2-dim);--dv-inactivegroup-visiblepanel-tab-background-color:var(--v2-surface);--dv-inactivegroup-visiblepanel-tab-color:var(--v2-fg);--dv-inactivegroup-hiddenpanel-tab-background-color:var(--v2-gutter);--dv-inactivegroup-hiddenpanel-tab-color:var(--v2-dim);--dv-tab-divider-color:var(--v2-border);--dv-separator-border:transparent;--dv-sash-color:transparent;--dv-active-sash-color:var(--v2-dim);height:100%;padding:var(--panel-gutter) var(--panel-gutter) var(--panel-gutter) 0;background-color:var(--v2-gutter);font-family:baltomobile,Balto,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}.shell-dockview.dv-dockview{background-color:var(--v2-gutter)}.shell-dockview .dv-default-tab-content{font-family:inherit}.shell-dockview .dv-split-view-container .dv-view:has(>.dv-groupview){border-radius:var(--panel-chrome-radius);box-sizing:border-box;overflow:hidden}.shell-dockview .dv-split-view-container .dv-view:has(>.dv-groupview):after{content:"";z-index:10;pointer-events:none;border:1px solid var(--v2-border);border-radius:inherit;box-sizing:border-box;position:absolute;inset:0}.shell-dockview .dv-view>.dv-groupview{border:none;border-radius:0;width:100%;height:100%}.shell-dockview .dv-split-view-container .dv-view:has(>.dv-groupview.dv-active-group):after{border-color:#6a6a6a}.shell-dockview .dv-resize-container:has(>.dv-groupview.dv-active-group):after{border-color:#6a6a6a}.shell-dockview .dv-resize-container:has(>.dv-groupview){border-radius:var(--panel-chrome-radius);box-sizing:border-box;overflow:hidden}.shell-dockview .dv-resize-container:has(>.dv-groupview):after{content:"";z-index:10;pointer-events:none;border:1px solid var(--v2-border);border-radius:inherit;box-sizing:border-box;position:absolute;inset:0}.shell-dockview .dv-resize-container .dv-groupview{border:none;border-radius:0;width:100%;height:100%}.shell-dockview .dv-tabs-container.dv-horizontal{align-items:stretch;display:flex}.shell-dockview .dv-tab{border:none;border-right:1px solid var(--dv-tab-divider-color);border-radius:0;align-self:stretch;height:100%;padding:0 5px 0 10px}.shell-dockview .dv-tab:not(:first-child){margin-left:0}.shell-dockview .dv-tab.dv-inactive-tab{border-bottom:1px solid var(--dv-tab-divider-color)}.shell-dockview .dv-tab.dv-active-tab{border-bottom:none}.shell-dockview .dv-tabs-and-actions-container .dv-void-container{border-bottom:1px solid var(--dv-tab-divider-color)}.shell-dockview .dv-tabs-and-actions-container .dv-right-actions-container{border-left:1px solid var(--dv-tab-divider-color);border-bottom:1px solid var(--dv-tab-divider-color);align-items:stretch}.shell-dockview .dv-tab .dv-default-tab-content{margin-right:6px}.shell-dockview .dv-tab .dv-default-tab-action{padding:2px}.shell-dockview .dv-tab .dv-default-tab-action .dv-svg{width:8px;height:8px;transform:translateY(1px)}.shell-dockview .dv-tab.dv-inactive-tab .dv-default-tab-action,.shell-dockview .dv-tab.dv-active-tab .dv-default-tab-action{color:var(--v2-dim)}.shell-dockview .dv-tabs-container.dv-horizontal .dv-tab:not(:first-child):before{display:none}.shell-dockview .dv-tab:focus:after,.shell-dockview .dv-tab:focus-within:after{display:none!important}.shell-dockview .dv-tabs-overflow-container{border:1px solid var(--dv-tab-divider-color);border-radius:var(--panel-chrome-radius);background:var(--v2-surface);min-width:180px;box-shadow:var(--v2-shadow-pop);gap:2px;padding:4px;overflow:hidden}.shell-dockview .dv-tabs-overflow-container .dv-tab{border-bottom:none;border-right:none;border-radius:6px;width:100%;padding:4px 8px 4px 10px}.shell-dockview .dv-tabs-overflow-container .dv-tab:hover{background:var(--v2-hover)}.shell-dockview .dv-tabs-overflow-container .dv-tab.dv-active-tab{background:var(--v2-raised)}.shell-dockview .dv-add-panel{align-items:center;height:100%;padding:0 3px;display:flex}.shell-dockview .dv-add-panel-btn{width:22px;height:22px;color:var(--dv-activegroup-visiblepanel-tab-color);cursor:pointer;background:0 0;border:none;border-radius:4px;justify-content:center;align-items:center;padding:0;display:flex}.shell-dockview .dv-add-panel-btn:hover{background:var(--v2-overlay-white-subtle)}.shell-dockview .dv-add-panel-btn svg{display:block}.dv-add-panel-menu{z-index:2147483000;background:var(--v2-surface);border:1px solid var(--v2-border);min-width:180px;box-shadow:var(--v2-shadow-pop);border-radius:8px;padding:4px;font-family:baltomobile,Balto,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;position:fixed;transform:translate(-100%)}.dv-add-panel-item{width:100%;color:var(--v2-fg);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:6px;align-items:center;gap:10px;padding:7px 10px;font-size:13px;display:flex}.dv-add-panel-item:hover{background:var(--v2-accent);color:var(--v2-white)}.dv-add-panel-item-icon{color:var(--v2-muted);flex:0 0 16px;justify-content:center;align-items:center;display:flex}.dv-add-panel-item:hover .dv-add-panel-item-icon{color:var(--v2-white)}.dv-add-panel-item-label{white-space:nowrap;flex:1}.empty-dock-state{z-index:20;padding:var(--panel-gutter);pointer-events:auto;justify-content:center;align-items:center;display:flex;position:absolute;inset:0}.empty-dock-card{background:var(--v2-surface);border:1px solid var(--v2-border);border-radius:var(--panel-chrome-radius);width:210px;box-shadow:var(--v2-shadow-pop);padding:6px}.empty-dock-title{color:var(--v2-muted);padding:7px 10px 8px;font-size:12px}.empty-dock-actions{flex-direction:column;gap:2px;display:flex}.empty-dock-item{width:100%;color:var(--v2-fg);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:6px;align-items:center;gap:10px;padding:8px 10px;font-size:13px;display:flex}.empty-dock-item:hover{background:var(--v2-accent);color:var(--v2-white)}.empty-dock-item:hover .dv-add-panel-item-icon{color:var(--v2-white)}.panel-error{height:100%;color:var(--v2-muted);flex-direction:column;align-items:flex-start;gap:8px;padding:14px 16px;font-size:13px;display:flex;overflow:auto}.panel-error-title{color:var(--v2-fg)}.panel-error-msg{white-space:pre-wrap;word-break:break-word;max-width:100%;color:var(--v2-muted);margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.panel-error-retry{font:inherit;border:1px solid var(--v2-border);background:var(--v2-raised);color:var(--v2-fg);cursor:pointer;border-radius:4px;padding:3px 10px;font-size:12px}.panel-error-retry:hover{background:var(--v2-hover)}.deck-panel{background:var(--v2-surface);width:100%;height:100%}.deck-frame{border:0;width:100%;height:100%;display:block}.play-panel{background:var(--v2-surface);flex-direction:column;width:100%;height:100%;display:flex}.play-stage{flex:auto;justify-content:center;align-items:center;min-height:0;padding:20px;display:flex;container-type:size}.play-frame-shell{aspect-ratio:5/7;border-radius:4%/2.85714%;width:min(100cqw,71.4286cqh);height:min(100cqh,140cqw);overflow:hidden}.play-frame-shell .deck-frame{width:100%;height:100%}.play-logs{border-top:1px solid var(--v2-border);background:var(--v2-surface);color:var(--v2-secondary);flex:none;font:12px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace}.play-logs-header{justify-content:space-between;align-items:center;height:28px;padding:0 8px;display:flex}.play-logs-toggle{color:var(--v2-muted);cursor:pointer;font:inherit;text-transform:uppercase;letter-spacing:.04em;background:0 0;border:0;align-items:center;gap:6px;padding:0;font-size:11px;display:inline-flex}.play-logs-caret{width:10px;color:var(--v2-muted);display:inline-block}.play-logs-count{color:var(--v2-muted)}.play-logs-actions{align-items:center;gap:6px;display:flex}.play-logs-clear{color:var(--v2-muted);cursor:pointer;font:inherit;background:0 0;border:0;padding:2px 4px;font-size:11px}.play-logs-clear:hover{color:var(--v2-secondary)}.play-logs-btn{width:26px;height:22px;color:var(--v2-secondary);border:1px solid var(--v2-overlay-white-border);cursor:pointer;background:0 0;border-radius:6px;justify-content:center;align-items:center;padding:0;display:inline-flex}.play-logs-btn:hover{background:var(--v2-overlay-white-hover);color:var(--v2-white)}.play-logs-body{border-top:1px solid var(--v2-raised);max-height:200px;padding:4px 10px 8px;overflow-y:auto}.play-logs-line{white-space:pre-wrap;word-break:break-word}.play-logs-warn{color:var(--v2-warn)}.play-logs-error{color:var(--v2-error)}.play-logs-empty{color:var(--v2-dim)}.term-panel{width:100%;height:100%;position:relative}.term-host{overscroll-behavior:contain;padding:6px;position:absolute;inset:0}.shell-root{--operator-pad:10px;--composer-reserve:88px;background:var(--v2-gutter);height:100%;position:relative}.shell-root .shell-dockview{height:100%;transition:margin-left .18s,width .18s,opacity .12s}body.operator-resizing .shell-root .shell-dockview{transition:none}.shell-root.dock-hidden .shell-dockview{opacity:0}.shell-root:not(.anim-ready) .shell-dockview,.shell-root:not(.anim-ready) #chat-host{transition:none}.shell-root.docked .shell-dockview{margin-left:var(--operator-col,400px);width:calc(100% - var(--operator-col,400px))!important}.shell-root.floating .shell-dockview{margin-left:60px;width:calc(100% - 60px)!important}#chat-host{width:var(--operator-col,400px);background:var(--v2-gutter);color:var(--v2-fg);z-index:10;flex-direction:column;font-family:Balto,system-ui,-apple-system,sans-serif;transition:background-color .18s;display:flex;position:absolute;top:0;bottom:0;left:0}body.operator-resizing #chat-host{transition:none}.shell-root.floating #chat-host{pointer-events:none;z-index:2147482500;background:0 0;width:380px;max-width:86vw}.operator-resize{top:0;bottom:0;left:var(--operator-col,400px);cursor:col-resize;z-index:30;width:8px;margin-left:-4px;position:absolute}body.operator-resizing,body.operator-resizing *{cursor:col-resize;-webkit-user-select:none!important;user-select:none!important}body.shell-sash-resizing,body.shell-sash-resizing *{-webkit-user-select:none!important;user-select:none!important}.shell-root.floating #chat-messages{pointer-events:none;justify-content:flex-end;padding:0 0 0 60px;position:absolute;inset:0 0 88px}.shell-root.floating #chat-messages .chat-bubbles{pointer-events:auto;flex-direction:column;gap:4px;display:flex}.shell-root.floating #chat-pending,.shell-root.floating .chat-input .ta,.shell-root.floating .chat-input .chat-queue{pointer-events:auto}.shell-root.floating .chat-input{z-index:6;pointer-events:none;margin-top:auto;padding-left:60px;padding-right:0;position:relative}.shell-root.floating #chat-host .chat-input.collapsed{pointer-events:none;padding-bottom:13px}.shell-root.floating #chat-host .chat-input.collapsed.revealed{pointer-events:auto}.shell-root.floating #chat-host .chat-input.collapsed .ta{cursor:pointer;opacity:0;pointer-events:none;border-radius:19px;justify-content:center;align-items:center;gap:0;width:38px;height:38px;min-height:0;padding:5px;transform:translateY(6px)}.shell-root.floating #chat-host .chat-input.collapsed.revealed .ta{opacity:1;pointer-events:auto;transform:none}.shell-root.floating #chat-host .chat-input.collapsed .ta-text,.shell-root.floating #chat-host .chat-input.collapsed .ta-bottom,.shell-root.floating #chat-host .chat-input.collapsed .chat-queue,.shell-root.floating #chat-host:not(.chat-expanded) #chat-pending,#chat-host .chat-input .collapse-icon{display:none}.shell-root.floating #chat-host .chat-input.collapsed .collapse-icon{width:28px;height:28px;color:var(--v2-muted);flex-shrink:0;justify-content:center;align-items:center;display:flex}#chat-host .chat-input .collapse-icon svg{width:20px;height:20px;display:block}.shell-root.floating #chat-host .chat-input.collapsed .ta:hover .collapse-icon{color:var(--v2-fg)}.shell-root.floating #chat-host .msg,.shell-root.floating #chat-host .assistant-turn{transition:opacity .55s}.shell-root.floating #chat-host .msg.fading,.shell-root.floating #chat-host .assistant-turn.fading{opacity:0;pointer-events:none}@media (prefers-reduced-motion:reduce){.shell-root.floating #chat-host .msg,.shell-root.floating #chat-host .assistant-turn{transition:none}}.shell-root.floating #chat-host.rail-engaged #chat-messages{opacity:0;pointer-events:none;transition:opacity .14s}.operator-avatar{background:var(--v2-raised);width:36px;height:36px;color:var(--v2-fg);border:2px solid var(--v2-avatar-ring);box-shadow:var(--v2-shadow-pop);cursor:pointer;pointer-events:auto;z-index:80;border-radius:50%;justify-content:center;align-items:center;padding:0;display:flex;position:absolute;bottom:14px;left:12px;overflow:hidden}.operator-avatar:hover{border-color:var(--v2-avatar-ring-hover)}.operator-avatar svg{display:block}.operator-avatar-img{object-fit:cover;border-radius:50%;width:100%;height:100%;display:block}.operator-avatar.active{border-color:var(--v2-running);box-shadow:0 0 0 3px var(--v2-running-ring), var(--v2-shadow-pop)}.operator-gutter{pointer-events:auto;z-index:5;width:60px;max-height:calc(100% - 56px);position:absolute;top:0;left:0;overflow:visible}#chat-host .operator-gutter .task-stack{scrollbar-width:none;-ms-overflow-style:none;flex-direction:column;width:100%;max-height:100%;display:flex;overflow-y:auto}.shell-root.floating #chat-host.rail-engaged .operator-gutter .task-stack{overflow:visible}#chat-host .operator-gutter .task-stack::-webkit-scrollbar{width:0;height:0}#chat-host .operator-gutter .task-row{padding:5px 14px}#chat-host .operator-gutter .task:hover,#chat-host .operator-gutter .task.open{background:var(--v2-overlay-task);width:344px;box-shadow:inset 0 0 0 1px var(--v2-border), var(--v2-shadow-pop);z-index:30;transform:translate(8px)}#chat-host .operator-gutter .task:hover .task-row,#chat-host .operator-gutter .task.open .task-row{gap:10px;padding:5px 6px}#chat-host .operator-gutter .task-meta{opacity:0;pointer-events:none;transition:opacity .14s}#chat-host .operator-gutter .task:hover .task-meta,#chat-host .operator-gutter .task.open .task-meta{opacity:1;pointer-events:auto}#chat-host .operator-gutter .task-name,#chat-host .operator-gutter .task-sub,#chat-host .operator-gutter .task-body{text-shadow:var(--v2-text-shadow-float)}#chat-host .settings-popover{z-index:2147483000;background:var(--v2-surface);width:390px;max-width:calc(100vw - 24px);color:var(--v2-fg);border:1px solid var(--v2-border);box-shadow:var(--v2-shadow-pop);border-radius:8px;padding:10px 12px;font-size:13px;position:fixed;bottom:70px;left:12px}#chat-host .settings-row{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:6px 10px;display:flex}#chat-host .settings-row+.settings-row{margin-top:8px}#chat-host .settings-label{white-space:nowrap}#chat-host .settings-seg{border:1px solid var(--v2-border);border-radius:4px;display:flex;overflow:hidden}#chat-host .settings-opt{font:inherit;background:var(--v2-surface);color:var(--v2-muted);cursor:pointer;white-space:nowrap;border:0;padding:5px 10px;font-size:13px}#chat-host .settings-opt+.settings-opt{border-left:1px solid var(--v2-border)}#chat-host .settings-opt:hover{color:var(--v2-fg)}#chat-host .settings-opt.active{background:var(--v2-accent);color:var(--v2-white)}#chat-host .settings-text{min-width:0;font:inherit;background:var(--v2-surface);color:var(--v2-fg);border:1px solid var(--v2-border);border-radius:4px;flex:auto;padding:5px 8px;font-size:13px}#chat-host .settings-text::placeholder{color:var(--v2-placeholder)}#chat-host .settings-text:focus{border-color:var(--v2-accent);outline:none}#chat-host .settings-row-stack{flex-direction:column;align-items:stretch;gap:4px;display:flex}#chat-host .settings-row-main{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:6px 10px;display:flex}#chat-host .settings-text-warn{border-color:var(--v2-warn)}#chat-host .settings-warning{color:var(--v2-warn);text-align:right;font-size:11px;line-height:1.35}#chat-host .settings-warning-suggest{appearance:none;font:inherit;color:var(--v2-warn);cursor:pointer;background:0 0;border:none;margin:0;padding:0;text-decoration:underline}#chat-host .settings-warning-suggest:hover{color:var(--v2-fg)}#chat-host .settings-select{max-width:60%;font:inherit;background:var(--v2-surface);color:var(--v2-fg);border:1px solid var(--v2-border);cursor:pointer;border-radius:4px;flex:0 auto;padding:5px 8px;font-size:13px}#chat-host .settings-select:focus{border-color:var(--v2-accent);outline:none}#chat-host .settings-select option{background:var(--v2-surface);color:var(--v2-fg)}#chat-host .settings-group+.settings-group{border-top:1px solid var(--v2-border);margin-top:12px;padding-top:12px}#chat-messages{scrollbar-width:none;-ms-overflow-style:none;flex-direction:column;flex:1 1 0;min-height:0;padding:0;font-size:14px;line-height:1.5;display:flex;overflow-y:auto}#chat-messages .chat-thread{opacity:0;flex-direction:column;transition:opacity .12s;display:flex}#chat-messages .chat-thread.ready{opacity:1}.shell-root.docked #chat-messages{-webkit-mask-image:linear-gradient(to bottom, var(--v2-gutter) calc(100% - var(--composer-reserve,88px)), transparent 100%);-webkit-mask-image:linear-gradient(to bottom, var(--v2-gutter) calc(100% - var(--composer-reserve,88px)), transparent 100%);mask-image:linear-gradient(to bottom, var(--v2-gutter) calc(100% - var(--composer-reserve,88px)), transparent 100%);padding:0}.shell-root.docked #chat-messages .chat-thread{padding-bottom:var(--composer-reserve,88px)}.shell-root.docked #chat-messages>:first-child{margin-top:auto}#chat-messages::-webkit-scrollbar{width:0;height:0}#chat-empty{color:var(--v2-muted)}#chat-host .msg{margin:5px 0}#chat-host .msg.user{text-align:right}#chat-host .msg.user span{background:var(--v2-white);color:var(--v2-ink);text-align:left;white-space:pre-wrap;word-break:break-word;border-radius:17px;max-width:85%;padding:7px 14px;display:inline-block}#chat-host .msg-image{border:1px solid var(--v2-border);border-radius:8px;max-width:220px;max-height:150px;margin:0 0 6px auto;display:block}#chat-host .assistant-turn{flex-direction:column;align-items:flex-start;gap:4px;margin:5px 0;display:flex}#chat-host .msg.assistant{background:var(--v2-accent);width:fit-content;color:var(--v2-white);word-break:break-word;border-radius:17px;max-width:85%;margin:0;padding:7px 14px}#chat-host .msg.assistant.errbubble{background:var(--v2-error-bg)}#chat-host .msg.assistant.streaming:after{content:"▌";opacity:.6;animation:1s step-end infinite chat-blink}@keyframes chat-blink{50%{opacity:0}}#chat-host .msg.toolline{color:var(--v2-muted);font-size:12px;font-family:var(--v2-mono);word-break:break-word;margin:4px 0}#chat-host .msg-activity{color:var(--v2-muted);font-size:12px;animation:1.4s ease-in-out infinite chat-pulse}@keyframes chat-pulse{50%{opacity:.35}}#chat-host .msg-interrupted,#chat-host .msg-error-detail{color:var(--v2-muted);font-size:12px}#chat-host .msg-error-detail summary{cursor:pointer;-webkit-user-select:none;user-select:none}#chat-host .msg-error-detail pre{background:var(--v2-overlay-scrim);white-space:pre-wrap;word-break:break-word;border-radius:6px;max-height:160px;margin:4px 0 0;padding:6px 8px;font-size:11px;overflow-y:auto}#chat-host .msg-thinking{color:var(--v2-muted);font-size:12px}#chat-host div.msg-thinking,#chat-host .msg-thinking summary{align-items:center;gap:8px;display:flex}#chat-host .msg-thinking summary{cursor:pointer;-webkit-user-select:none;user-select:none;list-style:none}#chat-host .msg-thinking summary::-webkit-details-marker{display:none}#chat-host .msg-thinking .thinking-caret{opacity:.7;border-top:4px solid #0000;border-bottom:4px solid #0000;border-left:5px solid;flex:none;width:0;height:0;transition:transform .12s}#chat-host .msg-thinking[open] .thinking-caret{transform:rotate(90deg)}#chat-host .msg-thinking .thinking-dots{gap:4px;display:inline-flex}#chat-host .msg-thinking .thinking-dots i{background:currentColor;border-radius:50%;width:6px;height:6px;animation:1.2s ease-in-out infinite thinking-bounce}#chat-host .msg-thinking .thinking-dots i:nth-child(2){animation-delay:.18s}#chat-host .msg-thinking .thinking-dots i:nth-child(3){animation-delay:.36s}#chat-host .msg-thinking .thinking-dots+.thinking-label{animation:1.4s ease-in-out infinite chat-pulse}@keyframes thinking-bounce{0%,80%,to{opacity:.3;transform:translateY(0)}40%{opacity:1;transform:translateY(-3px)}}@media (prefers-reduced-motion:reduce){#chat-host .msg-thinking .thinking-dots i,#chat-host .msg-thinking .thinking-label{animation:none}#chat-host .msg-thinking .thinking-dots i{opacity:.6}}#chat-host .msg-thinking-body{background:var(--v2-overlay-scrim);color:var(--v2-muted);border-radius:6px;max-height:160px;padding:0 12px;font-size:12px;overflow-y:auto}#chat-host .msg.md>:first-child,#chat-host .task-notes>:first-child{margin-top:0}#chat-host .msg.md>:last-child,#chat-host .task-notes>:last-child{margin-bottom:0}#chat-host .msg.md p:empty{display:none}#chat-host .msg.md p,#chat-host .task-notes p{margin:.4em 0}#chat-host .msg.md ul,#chat-host .msg.md ol,#chat-host .task-notes ul,#chat-host .task-notes ol{margin:.4em 0;padding-left:1.3em}#chat-host .msg.md li{margin:.1em 0}#chat-host .msg.md h1,#chat-host .msg.md h2,#chat-host .msg.md h3{margin:.5em 0 .3em;font-weight:700;line-height:1.25}#chat-host .msg.md h1{font-size:1.2em}#chat-host .msg.md h2{font-size:1.12em}#chat-host .msg.md h3{font-size:1.05em}#chat-host .msg.md a{color:var(--v2-white);text-underline-offset:2px;text-decoration:underline}#chat-host .msg.md code,#chat-host .task-notes code{font-family:var(--v2-mono);background:var(--v2-overlay-code);border-radius:4px;padding:.1em .35em;font-size:.9em}#chat-host .msg.md pre{background:var(--v2-overlay-code-block);white-space:pre-wrap;word-break:break-word;font-family:var(--v2-mono);border-radius:8px;margin:.5em 0;padding:8px 10px;font-size:.9em;line-height:1.4;overflow-x:auto}#chat-host .msg.md pre code{background:0 0;border-radius:0;padding:0}#chat-host .msg.md blockquote{border-left:3px solid var(--v2-overlay-white-quote);color:var(--v2-overlay-white-dim);margin:.5em 0;padding-left:.8em}.shell-root.docked #chat-host .operator-inset{min-height:0;padding:0 var(--operator-pad);flex-direction:column;flex:1 1 0;display:flex}.shell-root.docked #chat-host .chat-divider{background:var(--v2-border);flex:0 0 1px}.task-stack{gap:5px;padding-top:10px}#task-board{flex-direction:column;flex:none;padding-bottom:12px;display:flex}#chat-host .task{cursor:pointer;border-radius:8px;transition:background .12s,box-shadow .12s}#chat-host .task:hover,#chat-host .task.open{background:var(--v2-overlay-task);box-shadow:inset 0 0 0 1px var(--v2-border)}#chat-host .task-row{align-items:center;gap:10px;padding:5px 6px 5px 4px;display:flex;position:relative}#chat-host .task.open .task-row{align-items:flex-start}#chat-host .pie{border-radius:50%;flex:0 0 32px;width:32px;height:32px;padding:2px;display:flex;position:relative}#chat-host .pie .avatar{background:var(--v2-raised);width:100%;height:100%;color:var(--v2-gutter);border-radius:50%;justify-content:center;align-items:center;display:flex;overflow:hidden}#chat-host .pie .avatar .avatar-icon-wrap{justify-content:center;align-items:center;width:16px;height:16px;display:flex}#chat-host .pie .avatar .avatar-icon-wrap svg{width:16px;height:16px;display:block}#chat-host .task-meta{flex:1;min-width:0}#chat-host .task-head{align-items:center;gap:8px;display:flex}#chat-host .task.open .task-head{min-height:32px}#chat-host .task-text{flex:1;min-width:0}#chat-host .task-name{color:var(--v2-fg);white-space:nowrap;text-overflow:ellipsis;font-size:12px;font-weight:400;overflow:hidden}#chat-host .task-name .tn{color:var(--v2-head);font-weight:600}#chat-host .task-sub{color:var(--v2-muted);white-space:nowrap;text-overflow:ellipsis;font-variant-numeric:tabular-nums;margin-top:2px;font-size:10px;overflow:hidden}#chat-host .task-dismiss{border:1px solid var(--v2-border);color:var(--v2-muted);font:inherit;cursor:pointer;visibility:hidden;background:0 0;border-radius:6px;flex-shrink:0;padding:3px 10px;font-size:12px}#chat-host .task-dismiss:hover{color:var(--v2-fg);background:var(--v2-hover)}#chat-host .task:hover .task-dismiss{visibility:visible}#chat-host .task-body{color:var(--v2-fg);padding:0 0 4px;font-size:12px;display:none}#chat-host .task.open .task-body{display:block}#chat-host .task-notes{color:var(--v2-secondary);word-break:break-word;margin-top:6px;font-size:12px}#chat-host .task-notes code{font-size:12px}#chat-host .task-playtest-frames{margin-top:8px}#chat-host .task-playtest-frames-label{color:var(--v2-muted);margin-bottom:4px;font-size:11px}#chat-host .task-playtest-frames-row{flex-wrap:wrap;gap:6px;display:flex}#chat-host .task-playtest-frame{object-fit:cover;border:1px solid var(--v2-border);background:var(--v2-ink);border-radius:4px;width:64px;height:90px;display:block}#chat-host .task-feed{scrollbar-width:none;-ms-overflow-style:none;max-height:96px;color:var(--v2-secondary);cursor:default;word-break:break-word;-webkit-mask-image:linear-gradient(to bottom, transparent, var(--v2-gutter) 5px, var(--v2-gutter) 100%);-webkit-mask-image:linear-gradient(to bottom, transparent, var(--v2-gutter) 5px, var(--v2-gutter) 100%);mask-image:linear-gradient(to bottom, transparent, var(--v2-gutter) 5px, var(--v2-gutter) 100%);margin-top:6px;font-size:12px;line-height:1.5;overflow-y:auto}#chat-host .task-feed::-webkit-scrollbar{width:0;height:0}#chat-host .task-feed-tool{color:var(--v2-muted);font-family:var(--v2-mono);white-space:pre-wrap;padding-left:14px;font-size:12px}#chat-host .task-feed-msg{margin:0}#chat-host .task-feed-msg>:first-child{margin-top:0}#chat-host .task-feed-msg>:last-child{margin-bottom:0}#chat-host .task-feed-msg p{margin:0}#chat-host .task-feed-msg code{background:var(--v2-overlay-feed-code);font-family:var(--v2-mono);border-radius:3px;padding:0 3px;font-size:12px}.chat-input{flex:none;padding:10px 10px 10px 60px}.shell-root.docked .chat-input{padding:0 var(--operator-pad) 10px 60px;pointer-events:none;z-index:6;position:absolute;bottom:0;left:0;right:0}.shell-root.docked .chat-input .ta,.shell-root.docked .chat-input .chat-queue{pointer-events:auto}.shell-root.docked #chat-pending{left:60px;right:var(--operator-pad);bottom:var(--composer-reserve,88px);z-index:6;pointer-events:auto;padding:0;position:absolute}#chat-host .chat-input .ta{background:var(--v2-surface);border:1px solid var(--v2-border);border-radius:var(--panel-chrome-radius);flex-direction:column;gap:6px;width:100%;min-height:60px;padding:8px 4px;transition:width .3s cubic-bezier(.4,0,.2,1),height .3s cubic-bezier(.4,0,.2,1),border-radius .3s cubic-bezier(.4,0,.2,1),padding .3s cubic-bezier(.4,0,.2,1),opacity .18s,transform .18s;display:flex;overflow:hidden}#chat-input{width:100%;min-height:21px;color:var(--v2-fg);font:inherit;resize:none;scrollbar-width:none;-ms-overflow-style:none;background:0 0;border:none;outline:none;max-height:120px;padding:0 6px;font-size:14px;line-height:1.5;display:block;overflow-y:auto}#chat-input::-webkit-scrollbar{width:0;height:0}#chat-input::placeholder{color:var(--v2-muted)}#chat-host .chat-input .ta-bottom{justify-content:space-between;align-items:center;gap:8px;min-width:0;display:flex}#chat-host .composer-settings{flex:auto;min-width:0}#chat-host .composer-pill{max-width:100%;height:26px;color:var(--v2-dim);font:inherit;cursor:pointer;background:0 0;border:none;border-radius:6px;align-items:center;gap:5px;padding:0 6px;font-size:12px;display:inline-flex}#chat-host .composer-pill:hover{color:var(--v2-fg);background:var(--v2-hover)}#chat-host .composer-pill-label{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}#chat-host .composer-pill svg{flex-shrink:0;display:block}#chat-host .composer-pill .mode-caret{opacity:.7}#chat-send{width:26px;height:26px;color:var(--v2-muted);border:1px solid var(--v2-border);cursor:pointer;background:0 0;border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;margin-right:6px;padding:0;display:flex}#chat-send:hover{color:var(--v2-fg);background:var(--v2-hover)}#chat-send svg{display:block}#chat-pending{flex:none;gap:6px;padding:10px 10px 0;display:flex}#chat-pending img{border:1px solid var(--v2-border);cursor:pointer;border-radius:6px;height:44px}#chat-host .chat-input .chat-queue{flex-direction:column;gap:4px;margin-bottom:6px;display:flex}#chat-host .chat-input .queue-row{background:var(--v2-gutter);border:1px dashed var(--v2-border);color:var(--v2-muted);border-radius:8px;align-items:center;gap:8px;padding:5px 6px 5px 12px;font-size:12px;display:flex}#chat-host .chat-input .queue-snippet{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}#chat-host .chat-input .queue-send-now{border:1px solid var(--v2-border);color:var(--v2-muted);font:inherit;cursor:pointer;background:0 0;border-radius:6px;flex-shrink:0;padding:2px 8px;font-size:11px}#chat-host .chat-input .queue-send-now:hover{color:var(--v2-fg);background:var(--v2-hover)}#chat-host .chat-input .queue-remove{width:20px;height:20px;color:var(--v2-muted);cursor:pointer;background:0 0;border:none;border-radius:5px;flex-shrink:0;justify-content:center;align-items:center;padding:0;font-size:11px;display:flex}#chat-host .chat-input .queue-remove:hover{color:var(--v2-fg);background:var(--v2-hover)}#chat-send.stop{color:var(--v2-fg);border-color:var(--v2-fg)}#chat-send.stop:hover{color:var(--v2-ink);background:var(--v2-fg)}#chat-send:disabled{opacity:.45;cursor:default}#chat-send:disabled:hover{color:var(--v2-muted);background:0 0}#chat-host .picker{background:var(--v2-surface);border:1px dashed var(--v2-border);border-radius:12px;flex-direction:column;align-self:flex-start;gap:12px;width:100%;max-width:100%;margin:4px 0;padding:12px;display:flex}#chat-host .picker-locked{opacity:.72}#chat-host .picker-q{border:none;min-width:0;margin:0;padding:0}#chat-host .picker-q-label{color:var(--v2-head);margin:0 0 6px;padding:0;font-size:13px;font-weight:600}#chat-host .picker-options{flex-wrap:wrap;gap:6px;display:flex}#chat-host .picker-option{background:var(--v2-gutter);border:1px solid var(--v2-border);color:var(--v2-fg);cursor:pointer;border-radius:12px 12px 4px;align-items:center;gap:6px;padding:5px 10px;font-size:13px;line-height:1.3;display:inline-flex}#chat-host .picker:not(.picker-locked) .picker-option:hover{border-color:var(--v2-accent)}#chat-host .picker-option.is-checked{background:var(--v2-accent);border-color:var(--v2-accent);color:var(--v2-white)}#chat-host .picker-option input{accent-color:var(--v2-accent);cursor:inherit;margin:0}#chat-host .picker-locked .picker-option{cursor:default}#chat-host .picker-actions{justify-content:flex-end;display:flex}#chat-host .picker-submit{font:inherit;background:var(--v2-accent);color:var(--v2-white);border:1px solid var(--v2-accent);cursor:pointer;border-radius:8px;padding:6px 16px;font-size:13px}#chat-host .picker-submit:hover{background:var(--v2-accent-hover)}#chat-host .picker-skeleton{pointer-events:none}#chat-host .picker-skeleton-hint{color:var(--v2-muted);letter-spacing:.01em;font-size:12px}#chat-host .picker-skeleton-line,#chat-host .picker-skeleton-chip{background:linear-gradient(90deg, var(--v2-border) 0%, var(--v2-border) 50%, var(--v2-border) 100%);background-size:200% 100%;border-radius:6px;animation:1.3s ease-in-out infinite picker-shimmer;display:block}#chat-host .picker-skeleton-label{width:60%;height:11px;margin-bottom:8px}#chat-host .picker-skeleton-chip{border-radius:12px 12px 4px;height:26px}@keyframes picker-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}@media (prefers-reduced-motion:reduce){#chat-host .picker-skeleton-line,#chat-host .picker-skeleton-chip{animation:none}}.xterm,.xterm-viewport,.xterm-screen,.xterm-helpers{background-color:#0000!important}.xterm{overscroll-behavior:contain}.xterm-viewport{overscroll-behavior:contain;scrollbar-width:none;-ms-overflow-style:none}.xterm-viewport::-webkit-scrollbar{width:0;height:0}.xterm .xterm-scrollable-element>.scrollbar,.xterm .xterm-scrollable-element>.scrollbar.visible,.xterm .xterm-scrollable-element>.visible.scrollbar,.xterm .xterm-scrollable-element>.invisible.scrollbar,.xterm .xterm-scrollable-element>.xterm-scrollbar{opacity:0!important;pointer-events:none!important;width:0!important;min-width:0!important;height:0!important;min-height:0!important;display:none!important}.xterm .xterm-scrollable-element>.scrollbar>.slider,.xterm .xterm-scrollable-element>.scrollbar>.scra,.xterm .xterm-scrollable-element>.xterm-scrollbar>.xterm-slider{width:0!important;height:0!important;display:none!important}.xterm .xterm-scrollable-element>.shadow{display:none!important}.quick-open-backdrop{z-index:2147483100;justify-content:center;align-items:flex-start;padding-top:12vh;display:flex;position:fixed;inset:0}.quick-open{background:#232323;border:1px solid #3a3a3a;border-radius:8px;flex-direction:column;width:min(600px,90vw);max-height:60vh;display:flex;overflow:hidden;box-shadow:0 16px 48px #0009}.quick-open-input{color:#f0f0f0;background:#161616;border:1px solid #4a4a4a;border-radius:5px;outline:none;flex:none;margin:8px;padding:8px 10px;font-size:14px}.quick-open-input:focus{border-color:#5a8bd6}.quick-open-list{flex:auto;padding:4px;overflow-y:auto}.quick-open-item{color:#e6e6e6;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:4px;align-items:baseline;gap:8px;width:100%;padding:5px 8px;font-size:13px;display:flex}.quick-open-item.active{background:#37506f}.quick-open-name{white-space:nowrap;flex:none}.quick-open-dir{text-overflow:ellipsis;white-space:nowrap;color:#8a8a8a;flex:auto;min-width:0;font-size:12px;overflow:hidden}.quick-open-empty{color:#8a8a8a;text-align:center;padding:12px;font-size:13px}.quick-open-keys{color:#b0b0b0;white-space:nowrap;border:1px solid #4a4a4a;border-radius:4px;flex:none;margin-left:8px;padding:1px 6px;font-family:SFMono-Regular,Consolas,monospace;font-size:11px}.chord-hint{z-index:2147483200;color:#c7c7c7;background:#232323;border:1px solid #3a3a3a;border-radius:8px;align-items:center;gap:8px;padding:6px 12px;font-size:12px;display:flex;position:fixed;bottom:24px;left:50%;transform:translate(-50%);box-shadow:0 8px 24px #0000008c}.chord-hint kbd{color:#f0f0f0;background:#333;border:1px solid #4a4a4a;border-radius:4px;padding:2px 7px;font-family:SFMono-Regular,Consolas,monospace;font-size:12px}
@@ -4,8 +4,8 @@
4
4
  <meta charset="utf-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
6
  <title>Castle Editor</title>
7
- <script type="module" crossorigin src="/__castle/ide/assets/index-ByhgiJoP.js"></script>
8
- <link rel="stylesheet" crossorigin href="/__castle/ide/assets/index-D6hM_VlW.css">
7
+ <script type="module" crossorigin src="/__castle/ide/assets/index-BOgm5T3W.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/__castle/ide/assets/index-DonnH--m.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
Binary file
@@ -13,7 +13,7 @@ Do you already know what you want to make, or do you want to figure it out toget
13
13
  - Actor / behavior / scene framework on a fixed 500x700 canvas ("card").
14
14
  - Game logic lives in `behaviors/*.jsx` classes. A behavior's `static behaviorName` must match the component key used in scene JSON.
15
15
  - Editable screens live in `scenes/*.scene` files (plain JSON). Use a separate scene file per distinct screen, and switch with `scene.loadFromFile('name.scene')`.
16
- - Every actor is an instance of a **blueprint** (`blueprints/*.scene`) — see `## Blueprints` below. You don't have to manage this by hand: writing a plain inline actor (no `blueprint` field) still works and auto-migrates to a blueprint the next time the scene opens in the editor.
16
+ - Every actor is an instance of a **blueprint** (`blueprints/*.scene`) — see `## Blueprints` below. Always author the blueprint file yourself and reference it via `"blueprint"`. Don't write inline actors (full `components`, no `blueprint` field): the editor auto-migrates each one into its own new blueprint file on open, one per actor with no dedup, which litters the deck with junk blueprints.
17
17
  - Real game objects and scenery should usually be editable sprites: generate `.pxart` with `npm run draw -- name`, then place it via a `Sprite` component pointing at `drawings/name.pxart`. Dynamic UI/effects stay procedural.
18
18
  - This kit is plain JavaScript. Use `.jsx` for files with JSX, `.js` otherwise; do not add TypeScript files or a new build step.
19
19
  - After any code, scene, or drawing edit, run `npm run restart`.
@@ -72,51 +72,55 @@ A fresh `Behavior` instance is constructed per actor per frame from the actor's
72
72
 
73
73
  ## Scene file (`scenes/main.scene`, plain JSON)
74
74
 
75
- The simplest, always-safe way to write an actor is a plain inline actor no `blueprint` field, full `components`:
75
+ A scene is a background plus a list of actors. Every actor is an **instance of a blueprint** (see `## Blueprints`): a `blueprint` path plus sparse `components` overrides — usually just its `Layout` position:
76
76
 
77
77
  ```json
78
78
  {
79
79
  "background": "#1b2030",
80
80
  "actors": [
81
- {
82
- "id": "paddle",
83
- "components": {
84
- "Layout": { "x": 210, "y": 640, "width": 80, "height": 12 },
85
- "Sprite": { "file": "drawings/paddle.pxart" },
86
- "Collider": { "kind": "solid", "width": 80, "height": 12 },
87
- "Paddle": { "speed": 360 }
88
- }
89
- }
81
+ { "id": "paddle", "blueprint": "blueprints/paddle.scene", "components": { "Layout": { "x": 200, "y": 650 } } },
82
+ { "id": "brick-1", "blueprint": "blueprints/brick.scene", "components": { "Layout": { "x": 50, "y": 75 } } },
83
+ { "id": "brick-2", "blueprint": "blueprints/brick.scene", "components": { "Layout": { "x": 100, "y": 75 } } }
90
84
  ]
91
85
  }
92
86
  ```
93
87
 
94
- Rules: every actor needs a unique `id` (any string) and almost always a `Layout`. `components` keys are behavior names (the `static behaviorName`). Unspecified props fall back to that behavior's `defaultProps` omit optional fields (`z`, `rotation`, actor `name`, `tint: '#ffffffff'`, scene `name`) to keep scenes compact, especially when generating many actors. Add a behavior to an actor by adding its key to `components`; remove it by deleting the key.
95
-
96
- This inline shape is fine to keep writing by hand — see `## Blueprints` for what happens to it, and when referencing a blueprint directly is worth doing instead (e.g. many copies of the same enemy).
88
+ Rules: every actor needs a unique `id` (any string). An instance's `components` holds ONLY props that differ from its blueprint (merged per-property on top of the template); anything unspecified falls back to the blueprint, then to the behavior's `defaultProps`. Position (`Layout.x`/`y`/`rotation`) always lives on the instance. Omit optional fields (`z`, `rotation`, actor `name`, `tint: '#ffffffff'`, scene `name`) to keep scenes compact, especially when generating many actors.
97
89
 
98
90
  ## Blueprints
99
91
 
100
- Every actor placed through the editor is an **instance** of a **blueprint**: a `.scene` file under `blueprints/` whose single actor (`actors[0]`, no `id`) is the template. An instance actor looks like:
92
+ A **blueprint** is a `.scene` file under `blueprints/` whose single actor (`actors[0]`, no `id`) is the template:
101
93
 
102
94
  ```json
103
- { "id": "abc123", "blueprint": "blueprints/enemy.scene", "components": { "Layout": { "x": 100, "y": 200 } } }
95
+ {
96
+ "name": "Brick",
97
+ "actors": [
98
+ {
99
+ "components": {
100
+ "Layout": { "width": 50, "height": 25 },
101
+ "Sprite": { "file": "drawings/brick.pxart" },
102
+ "Collider": { "kind": "solid" },
103
+ "Brick": {}
104
+ }
105
+ }
106
+ ]
107
+ }
104
108
  ```
105
109
 
106
- `components` on an instance holds ONLY the props that differ from the blueprint (an override), merged on top of the blueprint's template per-property. Editing the blueprint file changes every instance that doesn't override that prop; editing an instance's own `Layout.x`/`y`/`rotation` never touches the blueprint (position/rotation are always instance-local — see `Layout.jsx`'s `propertyMeta`). This is entirely optional for you to manage directly:
110
+ Template `components` keys are behavior names (the `static behaviorName`); add a behavior to a kind of actor by adding its key here, remove it by deleting the key. The template almost always has a `Layout` with `width`/`height` (instances supply `x`/`y`).
107
111
 
108
- - **Plain inline actors (no `blueprint` field) still just work.** Write them the normal way; the editor mints a blueprint for each one automatically the first time a human opens that scene in the browser, and rewrites the actor into an instance. You never have to do this migration yourself.
109
- - **Reference a blueprint directly when it saves real duplication** e.g. 10 identical enemy actors: write one `blueprints/enemy.scene` (`{ "name": "Enemy", "actors": [{ "components": { "Sprite": {...}, "Collider": {...}, "Enemy": {...} } }] }`) and 10 scene actors that each just set `"blueprint": "blueprints/enemy.scene"` plus their own `Layout.x`/`y`. Don't bother doing this for a one-off actor plain inline is simpler and migrates fine later.
110
- - **When an actor is a distinct kind of thing** (not a one-off), author its blueprint yourself `blueprints/<meaningful>.scene` with a real `"name"`instead of leaving it inline for auto-migration to name; migration derives a reasonable name/file from the actor's `id` when it can, but a blueprint you write intentionally will always be clearer than one it infers.
112
+ - **Author one blueprint per kind of thing** `blueprints/<meaningful>.scene` with a real `"name"` and place instances that reference it. Do this even for a one-off actor: it costs one small file and keeps the deck's blueprint library intentional.
113
+ - Editing a blueprint file changes every instance that doesn't override that prop, across every scene so one `blueprints/player.scene` referenced from every level stays in sync everywhere. Editing an instance's own `Layout.x`/`y`/`rotation` never touches the blueprint (position/rotation are always instance-localsee `Layout.jsx`'s `propertyMeta`).
114
+ - **Never write inline actors** (full `components`, no `blueprint` field). They aren't a lighter-weight alternative: the editor auto-migrates every such actor into its OWN new blueprint file the first time a human opens the scene mechanically, one blueprint per actor, no dedup. That migration is a compatibility net for pre-blueprint decks, not an authoring workflow; leaning on it turns 10 inline enemies into 10 junk blueprints.
111
115
  - Never invent your own `blueprint` path pointing at a file you didn't also create — a dangling reference resolves to "no template" (the instance's own sparse `components` render alone, missing whatever it expected to inherit).
112
116
 
113
117
  ## Built-in behaviors
114
118
 
115
119
  - **Layout** — `{ x, y, width, height, z?, rotation? }`. Every actor needs one. `z` orders draw (low first). `rotation` is degrees about the center.
116
- - **Sprite** — `{ file: "drawings/foo.pxart", tint?: "#rrggbbaa", playing?: true, tag?: "" }`. Renders a `.pxart` pixel-art sprite scaled into the Layout box. `tint` multiplies; use white (`#ffffffff`) or omit for the original colors. Animated sprites play automatically; set `playing: false` to hold the first frame, or `tag` to play a named animation tag.
120
+ - **Sprite** — `{ file: "drawings/foo.pxart", tint?: "#rrggbbaa", playing?: true, tag?: "", mode?: 'cover'|'fit'|'stretch'|'tile', tileSize?: 50 }`. Renders a `.pxart` pixel-art sprite into the Layout box: scaled up preserving the art's aspect ratio to fill the whole box, cropping whatever overflows a mismatched box (`mode: 'cover'`, the default -- CSS object-fit: cover), scaled preserving the art's aspect ratio and centered so the whole sprite stays visible, letterboxing a mismatched box instead of cropping (`mode: 'fit'` -- CSS object-fit: contain), scaled to fill the box exactly and distorting the art when the aspect ratios don't match (`mode: 'stretch'`), or repeated (`mode: 'tile'`). `tint` multiplies; use white (`#ffffffff`) or omit for the original colors. Animated sprites play automatically; set `playing: false` to hold the first frame, or `tag` to play a named animation tag. Tile mode repeats the art at a fixed cell size (`tileSize` card units tall, width scaled by the art's aspect) instead of stretching it across the Layout box.
117
121
  - **Missing sprites fall back to a placeholder.** If `file` names a sprite that doesn't exist yet, it renders the fallback `drawings/cauldron.pxart` — so you can give an actor its REAL intended sprite name (`drawings/paddle.pxart`) right away and it shows the placeholder until that file is created. Reference real names from the start; don't wait for the art.
118
- - **Don't distort pixel art.** Keep an actor's Layout aspect ratio close to its sprite's native aspect ratio, and don't scale a sprite way up stretching a small sprite into a long/tall actor wrecks the pixels (a brick sprite stretched into a wall ruins the bricks). For long surfaces (walls, floors, platforms), make a sprite proportioned to the surface (or tile several actors) instead of stretching one.
119
- - **Collider** — `{ kind: 'solid'|'pickup', width, height, offsetX?, offsetY?, debug? }`. Just a rect; `offsetX`/`offsetY` move the collider from its centered position inside the actor's Layout (so `0,0` centers it). The framework does NOT auto-resolve collisions for you. Use it as data:
122
+ - **Fill the box, don't distort.** The default `mode: 'cover'` fills the Layout box with the art undistorted, cropping whatever overflows when the box aspect doesn't match the art's — so treat the Layout box like an image frame in a design tool: size it to frame what matters and keep the sprite's important content toward the center, since the edges may be cropped. Keeping an actor's Layout aspect ratio close to its sprite's native aspect ratio minimizes how much gets cropped. When the whole sprite must stay visible (nothing is safe to crop), use `mode: 'fit'`, which preserves the art and letterboxes the mismatched box instead. Avoid `mode: 'stretch'` for pixel art — filling a long/tall box by distorting wrecks the pixels (a brick sprite stretched into a wall ruins the bricks). For long surfaces (walls, floors, platforms), use `mode: 'tile'` on one actor to repeat the art at a fixed cell size instead of stretching or cropping a single sprite.
123
+ - **Collider** — `{ kind: 'solid'|'pickup', mode?: 'auto'|'manual', width, height, offsetX?, offsetY?, debug? }`. Just a rect; `offsetX`/`offsetY` nudge the collider from its default position (so `0,0` is the default). `mode: 'auto'` (the default) fits the rect to the actor's Sprite's opaque pixels, mapped through the Sprite's draw mode (`fit`'s letterboxed dest rect, `stretch`'s full Layout box, `cover`'s filled box clipped to the Layout box; `tile` mode and a missing/unresolved Sprite use the whole Layout box instead). `width`/`height` only apply in `mode: 'manual'` (a rect of that size, centered in the Layout box); they're ignored in `auto`. The framework does NOT auto-resolve collisions for you. Use it as data:
120
124
 
121
125
  ```jsx
122
126
  for (const other of scene.getActors()) {
@@ -1,14 +1,16 @@
1
1
  import React from 'react';
2
2
  import { Panel, SelectField } from '../engine/ui';
3
- import { AutoFields } from '../engine/autoInspector';
3
+ import { AutoFields, overrideProps } from '../engine/autoInspector';
4
+ import { getColliderRect, intersects } from '../engine/collider';
4
5
 
5
6
  export class Collider {
6
7
  static behaviorName = 'Collider';
7
8
 
8
9
  static defaultProps = {
9
10
  kind: 'solid',
10
- width: 32,
11
- height: 32,
11
+ mode: 'auto',
12
+ width: 50,
13
+ height: 50,
12
14
  offsetX: 0,
13
15
  offsetY: 0,
14
16
  debug: false,
@@ -18,9 +20,9 @@ export class Collider {
18
20
  this.props = props;
19
21
  }
20
22
 
21
- draw(actor, _scene, ctx, options) {
23
+ draw(actor, scene, ctx, options) {
22
24
  if (!options.showDebugColliders && !this.props.debug) return;
23
- const rect = getColliderRect(actor);
25
+ const rect = getColliderRect(actor, scene.sprites);
24
26
  if (!rect) return;
25
27
  ctx.save();
26
28
  ctx.strokeStyle = this.props.kind === 'pickup' ? '#ffe17a' : '#8db7ff';
@@ -29,45 +31,37 @@ export class Collider {
29
31
  ctx.restore();
30
32
  }
31
33
 
32
- static Inspector({ component, setComponent }) {
34
+ static Inspector({ component, setComponent, override }) {
33
35
  return (
34
- <Panel title="Collider">
36
+ <Panel title="Collider" overridden={override?.anyOverridden()}>
35
37
  <SelectField
36
38
  label="Kind"
37
39
  value={component.kind}
38
40
  onChange={(kind) => setComponent({ kind: kind })}
39
41
  options={['solid', 'pickup']}
42
+ {...overrideProps(override, 'kind')}
43
+ />
44
+ <SelectField
45
+ label="Mode"
46
+ value={component.mode}
47
+ onChange={(mode) => setComponent({ mode: mode })}
48
+ options={['auto', 'manual']}
49
+ {...overrideProps(override, 'mode')}
40
50
  />
41
51
  <AutoFields
42
52
  defaultProps={Collider.defaultProps}
43
53
  component={component}
44
54
  setComponent={setComponent}
45
- exclude={['kind']}
55
+ exclude={['kind', 'mode']}
56
+ override={override}
46
57
  />
47
58
  </Panel>
48
59
  );
49
60
  }
50
61
  }
51
62
 
52
- export function getColliderRect(actor) {
53
- const layout = actor.components.Layout;
54
- const collider = actor.components.Collider;
55
- if (!layout || !collider) return null;
56
- const width = collider.width ?? layout.width;
57
- const height = collider.height ?? layout.height;
58
- return {
59
- x: layout.x + (layout.width - width) / 2 + (collider.offsetX ?? 0),
60
- y: layout.y + (layout.height - height) / 2 + (collider.offsetY ?? 0),
61
- width,
62
- height,
63
- };
64
- }
65
-
66
- export function intersects(a, b) {
67
- return (
68
- a.x < b.x + b.width &&
69
- a.x + a.width > b.x &&
70
- a.y < b.y + b.height &&
71
- a.y + a.height > b.y
72
- );
73
- }
63
+ // Re-exported for callers that need the rect / overlap test outside a running
64
+ // scene (e.g. editors/SelectionOverlay.jsx, which passes the merged preview
65
+ // actors plus the sprites map). See engine/collider.js for the single
66
+ // implementation.
67
+ export { getColliderRect, intersects };
@@ -6,17 +6,20 @@ export class Layout {
6
6
  y: 0,
7
7
  z: 0,
8
8
  rotation: 0,
9
- width: 32,
10
- height: 32,
9
+ width: 50,
10
+ height: 50,
11
11
  };
12
12
 
13
- // Position/rotation never inherit from a blueprint: they're always written
14
- // as instance values at placement time, and a blueprint edit to its own
15
- // template x/y/rotation only affects newly placed instances, never moves
16
- // ones already placed. width/height/z default to inherited (absent here).
13
+ // Position/rotation/z never inherit from a blueprint: they're always written
14
+ // as instance values at placement time (z gets an explicit top-of-stack value
15
+ // on spawn), and a blueprint edit to its own template x/y/z/rotation only
16
+ // affects newly placed instances, never moves ones already placed. Because
17
+ // they're always instance-local, they're also never surfaced as blueprint
18
+ // "overrides" in the inspector. width/height default to inherited (absent).
17
19
  static propertyMeta = {
18
20
  x: { inherit: false },
19
21
  y: { inherit: false },
22
+ z: { inherit: false },
20
23
  rotation: { inherit: false },
21
24
  };
22
25
 
@@ -1,8 +1,9 @@
1
1
  import React from 'react';
2
2
  import { frameCount, renderSpriteFrame } from '../engine/pxart';
3
3
  import { renderSmoothSpriteFrame } from '../engine/pxartSmooth';
4
+ import { spriteDestRect } from '../engine/spriteGeometry';
4
5
  import { Panel, SelectField } from '../engine/ui';
5
- import { AutoFields } from '../engine/autoInspector';
6
+ import { AutoFields, overrideProps } from '../engine/autoInspector';
6
7
  import { parseTint, tintImageData } from './tint';
7
8
 
8
9
  // Runtime behavior for the pixel-art Sprite format (.pxart). It looks up the
@@ -27,6 +28,8 @@ export class Sprite {
27
28
  tint: '#ffffffff',
28
29
  playing: true,
29
30
  tag: '',
31
+ mode: 'cover',
32
+ tileSize: 50,
30
33
  };
31
34
 
32
35
  constructor(props) {
@@ -66,32 +69,159 @@ export class Sprite {
66
69
  // corner-rounded vector fills (see engine/pxartSmooth.js); blit those with
67
70
  // smoothing on so downscaling to the Layout box stays antialiased. Plain
68
71
  // pixel sprites (`cornerRadius === 0`) keep nearest-neighbor blitting.
69
- ctx.imageSmoothingEnabled = sprite.cornerRadius > 0;
70
- ctx.drawImage(canvas, layout.x, layout.y, layout.width, layout.height);
71
- ctx.imageSmoothingEnabled = prevSmoothing;
72
+ const smoothing = sprite.cornerRadius > 0;
73
+
74
+ // Snap the destination rect to whole device pixels so tiles that abut
75
+ // exactly in card units (e.g. adjacent 100-unit-wide tiles) land on the
76
+ // same device-pixel edge instead of each getting its own antialiased
77
+ // partial-coverage edge, which otherwise leaves faint hairline seams
78
+ // between them. Rounding each of the four device-space coordinates
79
+ // independently (rather than rounding position+size) is what makes two
80
+ // neighbors sharing a card-unit edge compute and round to the identical
81
+ // device pixel. Skipped when the ctx is rotated/skewed (nonzero b or c,
82
+ // set by the runtime for `Layout.rotation`), since a rotated rect has no
83
+ // axis-aligned device edges to snap to.
84
+ const transform = ctx.getTransform();
85
+ const tiling = this.props.mode === 'tile';
86
+ // `cover` scales the art to fill the box preserving aspect ratio, so `dest`
87
+ // overflows the Layout box and the overflow must be clipped to the box.
88
+ const covering = this.props.mode === 'cover';
89
+ // Everything downstream (snapping, tiling's clip box) works off `dest`: the
90
+ // Layout box itself for every mode except `fit`/`cover`, which resize to the
91
+ // art's own aspect ratio (see `spriteDestRect`).
92
+ const dest = spriteDestRect(this.props.mode, layout, canvas);
93
+ if (transform.b === 0 && transform.c === 0) {
94
+ const x0 = dest.x * transform.a + transform.e;
95
+ const y0 = dest.y * transform.d + transform.f;
96
+ const x1 = (dest.x + dest.width) * transform.a + transform.e;
97
+ const y1 = (dest.y + dest.height) * transform.d + transform.f;
98
+ const rx0 = Math.round(x0);
99
+ const ry0 = Math.round(y0);
100
+ const rx1 = Math.round(x1);
101
+ const ry1 = Math.round(y1);
102
+ ctx.save();
103
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
104
+ ctx.imageSmoothingEnabled = smoothing;
105
+ if (tiling) {
106
+ drawTilesSnapped(ctx, canvas, this.props.tileSize, dest, transform, x0, y0, rx0, ry0, rx1, ry1);
107
+ } else {
108
+ // Clip cover's overflow to the snapped Layout box (undone by restore).
109
+ if (covering) {
110
+ const lx0 = Math.round(layout.x * transform.a + transform.e);
111
+ const ly0 = Math.round(layout.y * transform.d + transform.f);
112
+ const lx1 = Math.round((layout.x + layout.width) * transform.a + transform.e);
113
+ const ly1 = Math.round((layout.y + layout.height) * transform.d + transform.f);
114
+ ctx.beginPath();
115
+ ctx.rect(lx0, ly0, lx1 - lx0, ly1 - ly0);
116
+ ctx.clip();
117
+ }
118
+ ctx.drawImage(canvas, rx0, ry0, rx1 - rx0, ry1 - ry0);
119
+ }
120
+ ctx.restore();
121
+ } else {
122
+ ctx.imageSmoothingEnabled = smoothing;
123
+ if (tiling) {
124
+ drawTilesUnsnapped(ctx, canvas, this.props.tileSize, dest);
125
+ } else if (covering) {
126
+ // Rotated: clip cover's overflow to the Layout box in card units.
127
+ ctx.save();
128
+ ctx.beginPath();
129
+ ctx.rect(layout.x, layout.y, layout.width, layout.height);
130
+ ctx.clip();
131
+ ctx.drawImage(canvas, dest.x, dest.y, dest.width, dest.height);
132
+ ctx.restore();
133
+ } else {
134
+ ctx.drawImage(canvas, dest.x, dest.y, dest.width, dest.height);
135
+ }
136
+ ctx.imageSmoothingEnabled = prevSmoothing;
137
+ }
72
138
  }
73
139
 
74
- static Inspector({ component, setComponent, files }) {
140
+ static Inspector({ component, setComponent, files, override }) {
75
141
  const spriteFiles = getSpriteFiles(files);
76
142
  return (
77
- <Panel title="Sprite">
143
+ <Panel title="Sprite" overridden={override?.anyOverridden()}>
78
144
  <SelectField
79
145
  label="File"
80
146
  value={component.file}
81
147
  onChange={(file) => setComponent({ file })}
82
148
  options={spriteFiles}
149
+ {...overrideProps(override, 'file')}
150
+ />
151
+ <SelectField
152
+ label="Mode"
153
+ value={component.mode}
154
+ onChange={(mode) => setComponent({ mode })}
155
+ options={['stretch', 'fit', 'cover', 'tile']}
156
+ {...overrideProps(override, 'mode')}
83
157
  />
84
158
  <AutoFields
85
159
  defaultProps={Sprite.defaultProps}
86
160
  component={component}
87
161
  setComponent={setComponent}
88
- only={['playing', 'tint']}
162
+ only={['playing', 'tint', 'tileSize']}
163
+ override={override}
89
164
  />
90
165
  </Panel>
91
166
  );
92
167
  }
93
168
  }
94
169
 
170
+ // Guard against non-finite or non-positive tileSize props (e.g. cleared
171
+ // inspector fields), falling back to one 50-unit grid cell.
172
+ function validTileSize(value) {
173
+ return Number.isFinite(value) && value > 0 ? value : 50;
174
+ }
175
+
176
+ // Repeat the sprite in device space, clipped to the snapped box. Tile edges
177
+ // are rounded independently from the box's unrounded device origin (x0/y0)
178
+ // using the same per-edge-rounding discipline as the box snap in `draw`, so
179
+ // neighboring tiles within this actor land on identical device pixels with
180
+ // no hairline seams.
181
+ function drawTilesSnapped(ctx, canvas, tileSize, layout, transform, x0, y0, rx0, ry0, rx1, ry1) {
182
+ const cellHeight = validTileSize(tileSize);
183
+ const cellWidth = cellHeight * (canvas.width / canvas.height);
184
+ const cellDeviceWidth = cellWidth * transform.a;
185
+ const cellDeviceHeight = cellHeight * transform.d;
186
+ const cols = Math.ceil(layout.width / cellWidth);
187
+ const rows = Math.ceil(layout.height / cellHeight);
188
+ ctx.save();
189
+ ctx.beginPath();
190
+ ctx.rect(rx0, ry0, rx1 - rx0, ry1 - ry0);
191
+ ctx.clip();
192
+ for (let row = 0; row < rows; row++) {
193
+ const edgeY0 = Math.round(y0 + row * cellDeviceHeight);
194
+ const edgeY1 = Math.round(y0 + (row + 1) * cellDeviceHeight);
195
+ for (let col = 0; col < cols; col++) {
196
+ const edgeX0 = Math.round(x0 + col * cellDeviceWidth);
197
+ const edgeX1 = Math.round(x0 + (col + 1) * cellDeviceWidth);
198
+ ctx.drawImage(canvas, edgeX0, edgeY0, edgeX1 - edgeX0, edgeY1 - edgeY0);
199
+ }
200
+ }
201
+ ctx.restore();
202
+ }
203
+
204
+ // Rotated actors have no axis-aligned device edges to snap to, so tile
205
+ // unsnapped in card units, matching the unsnapped stretch fallback in `draw`.
206
+ function drawTilesUnsnapped(ctx, canvas, tileSize, layout) {
207
+ const cellHeight = validTileSize(tileSize);
208
+ const cellWidth = cellHeight * (canvas.width / canvas.height);
209
+ const cols = Math.ceil(layout.width / cellWidth);
210
+ const rows = Math.ceil(layout.height / cellHeight);
211
+ ctx.save();
212
+ ctx.beginPath();
213
+ ctx.rect(layout.x, layout.y, layout.width, layout.height);
214
+ ctx.clip();
215
+ for (let row = 0; row < rows; row++) {
216
+ const ty = layout.y + row * cellHeight;
217
+ for (let col = 0; col < cols; col++) {
218
+ const tx = layout.x + col * cellWidth;
219
+ ctx.drawImage(canvas, tx, ty, cellWidth, cellHeight);
220
+ }
221
+ }
222
+ ctx.restore();
223
+ }
224
+
95
225
  // Cache of native-resolution offscreen canvases keyed by sprite, then by
96
226
  // `${frameIndex}|${tint}`. A sprite edit produces a fresh Sprite object, so a
97
227
  // new object naturally misses the WeakMap and rebuilds.