castle-web-cli 0.4.75 → 0.4.76

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 (68) hide show
  1. package/dist/agent-prompts.d.ts +4 -0
  2. package/dist/agent-prompts.js +20 -8
  3. package/dist/agent.js +301 -28
  4. package/dist/castle-host/host.js +59 -5
  5. package/dist/commonInstructions.d.ts +1 -1
  6. package/dist/commonInstructions.js +4 -0
  7. package/dist/ide.d.ts +1 -0
  8. package/dist/ide.js +250 -1
  9. package/dist/init.js +46 -4
  10. package/dist/save-deck.js +8 -1
  11. package/dist/serve.js +27 -1
  12. package/dist/shell/assets/index-DNWEQd4R.js +141 -0
  13. package/dist/shell/assets/{index-WNbOHPBj.css → index-DuKq-Grp.css} +1 -1
  14. package/dist/shell/index.html +2 -2
  15. package/kits/basic-2d/CLAUDE.md +13 -5
  16. package/kits/basic-2d/castle.json +15 -0
  17. package/kits/basic-2d/drawings/pig.pxart +22 -55
  18. package/kits/basic-2d/editors/PxArtEditor.jsx +237 -4
  19. package/kits/basic-2d/editors/SingleEditor.jsx +6 -51
  20. package/kits/basic-2d/editors/pixelEditorChrome.jsx +17 -11
  21. package/kits/basic-2d/editors/pixelGeometry.js +95 -0
  22. package/kits/basic-2d/editors/pixelInspector.jsx +229 -51
  23. package/kits/basic-2d/editors/pxArtTools.js +109 -1
  24. package/kits/basic-2d/engine/ScenePlayer.jsx +11 -160
  25. package/kits/basic-2d/engine/ui.jsx +15 -0
  26. package/kits/basic-2d/engine/ui.module.css +44 -117
  27. package/kits/basic-2d/main.jsx +6 -10
  28. package/package.json +10 -1
  29. package/dist/shell/assets/index-Dfn29Bkt.js +0 -108
  30. package/kits/basic-2d/editors/App.jsx +0 -226
  31. package/kits/basic-2d/editors/CodeEditor.jsx +0 -79
  32. package/kits/basic-2d/editors/FileBrowser.jsx +0 -349
  33. package/kits/basic-2d/editors/codeTheme.js +0 -135
  34. package/kits/basic-2d/engine/playConsole.js +0 -66
  35. package/kits/basic-3d/.prettierrc +0 -8
  36. package/kits/basic-3d/CLAUDE.md +0 -162
  37. package/kits/basic-3d/behaviors/Camera.jsx +0 -56
  38. package/kits/basic-3d/behaviors/Collider.jsx +0 -78
  39. package/kits/basic-3d/behaviors/Mesh.jsx +0 -82
  40. package/kits/basic-3d/behaviors/Model.jsx +0 -61
  41. package/kits/basic-3d/behaviors/Transform.jsx +0 -35
  42. package/kits/basic-3d/editors/App.jsx +0 -147
  43. package/kits/basic-3d/editors/CodeEditor.jsx +0 -112
  44. package/kits/basic-3d/editors/FileBrowser.jsx +0 -143
  45. package/kits/basic-3d/editors/ModelEditor.jsx +0 -400
  46. package/kits/basic-3d/editors/PlayOnly.jsx +0 -22
  47. package/kits/basic-3d/editors/SceneEditor.jsx +0 -1081
  48. package/kits/basic-3d/editors/behaviorRegistry.js +0 -24
  49. package/kits/basic-3d/editors/editorHistory.js +0 -52
  50. package/kits/basic-3d/editors/viewportRig.js +0 -90
  51. package/kits/basic-3d/engine/ScenePlayer.jsx +0 -58
  52. package/kits/basic-3d/engine/SceneUI.jsx +0 -67
  53. package/kits/basic-3d/engine/SceneViewport.jsx +0 -102
  54. package/kits/basic-3d/engine/autoInspector.jsx +0 -51
  55. package/kits/basic-3d/engine/files.js +0 -73
  56. package/kits/basic-3d/engine/scene.js +0 -502
  57. package/kits/basic-3d/engine/threeUtil.js +0 -260
  58. package/kits/basic-3d/engine/ui.jsx +0 -352
  59. package/kits/basic-3d/engine/ui.module.css +0 -944
  60. package/kits/basic-3d/eslint.config.js +0 -51
  61. package/kits/basic-3d/index.html +0 -11
  62. package/kits/basic-3d/main.jsx +0 -10
  63. package/kits/basic-3d/models/block.model +0 -14
  64. package/kits/basic-3d/package-lock.json +0 -2713
  65. package/kits/basic-3d/package.json +0 -41
  66. package/kits/basic-3d/pnpm-lock.yaml +0 -1769
  67. package/kits/basic-3d/scenes/main.scene +0 -76
  68. package/kits/basic-3d/vite.config.js +0 -1
@@ -1,21 +1,15 @@
1
- import React, { useCallback, useEffect, useRef, useState } from 'react';
2
- import { createPortal } from 'react-dom';
1
+ import React, { useCallback, useEffect, useRef } from 'react';
3
2
  import { configureSceneCanvas, makeScene } from './scene';
4
3
  import { SceneUI } from './SceneUI';
5
- import { cx, Icon, styles } from './ui';
6
- import { usePlayLogs } from './playConsole';
7
4
  // Engine-level scene player: mount a `SceneRuntime` against a canvas, wire
8
5
  // keyboard / pointer input, run the update+draw loop, and render the
9
6
  // behavior-driven UI overlay. No game logic lives here -- behaviors and
10
- // scenes are the place for that.
7
+ // scenes are the place for that. The dev logs drawer is a builtin shell panel
8
+ // now (cli/src/shell), not rendered here.
11
9
  export function ScenePlayer({ sceneData, sprites, behaviorClasses, onFirstFrame }) {
12
10
  const canvasRef = useRef(null);
13
11
  const runtimeRef = useRef(null);
14
- // Bumping this re-runs the mount effect below, which tears down the running
15
- // loop/runtime and rebuilds a fresh scene from the same data -- a clean restart.
16
- const [runToken, setRunToken] = useState(0);
17
12
  const getRuntime = useCallback(() => runtimeRef.current, []);
18
- const restart = useCallback(() => setRunToken((token) => token + 1), []);
19
13
  useEffect(() => {
20
14
  const canvas = canvasRef.current;
21
15
  if (!canvas) return undefined;
@@ -61,9 +55,7 @@ export function ScenePlayer({ sceneData, sprites, behaviorClasses, onFirstFrame
61
55
  canvas.addEventListener('pointerup', onPointerUp);
62
56
  canvas.addEventListener('pointercancel', onPointerUp);
63
57
  canvas.focus();
64
- // Only signal first-frame readiness on the initial run; a restart shouldn't
65
- // re-fire the host launcher reveal.
66
- const stopLoop = startPlayerLoop(canvas, ctx, runtime, runToken === 0 ? onFirstFrame : undefined);
58
+ const stopLoop = startPlayerLoop(canvas, ctx, runtime, onFirstFrame);
67
59
  return () => {
68
60
  stopLoop();
69
61
  window.removeEventListener('keydown', onKeyDown);
@@ -75,156 +67,15 @@ export function ScenePlayer({ sceneData, sprites, behaviorClasses, onFirstFrame
75
67
  runtimeRef.current = null;
76
68
  };
77
69
  // eslint-disable-next-line react-hooks/exhaustive-deps
78
- }, [runToken]);
79
- return (
80
- <>
81
- <div style={{ position: 'fixed', inset: 0, background: '#000' }}>
82
- <canvas
83
- ref={canvasRef}
84
- tabIndex={0}
85
- style={{ width: '100%', height: '100%', display: 'block', outline: 'none' }}
86
- />
87
- <SceneUI getRuntime={getRuntime} />
88
- </div>
89
- {/* Portal to <body> so the console drawer escapes the SDK's card-sized,
90
- transformed `#root > *` wrapper and pins to the panel, outside the
91
- play preview. */}
92
- {createPortal(<PlayConsole onRestart={restart} />, document.body)}
93
- </>
94
- );
95
- }
96
- function PlayConsole({ onRestart }) {
97
- const { logs, clearLogs } = usePlayLogs();
98
- const [open, setOpen] = useState(false);
99
- const rootRef = useRef(null);
100
- const bodyRef = useRef(null);
101
- // Reserve the drawer's footprint by shrinking + lifting the SDK deck card so it
102
- // sits fully above the drawer (visible + interactive) instead of behind it.
103
- // Driven by the live drawer height; recomputed on toggle (height change via the
104
- // ResizeObserver) and on window/card resize.
105
- useEffect(() => {
106
- const el = rootRef.current;
107
- if (!el) return undefined;
108
- const docEl = document.documentElement;
109
- docEl.dataset.castleLogs = '';
110
- const TOP_MARGIN = 16;
111
- const MIN_CARD_SCALE = 0.2;
112
- const apply = () => {
113
- const drawerHeight = el.offsetHeight;
114
- const cs = getComputedStyle(docEl);
115
- const fullW = parseFloat(cs.getPropertyValue('--castle-card-w'));
116
- const fullH = parseFloat(cs.getPropertyValue('--castle-card-h'));
117
- docEl.style.setProperty('--castle-logs-shift', `${drawerHeight / 2}px`);
118
- // Only resize the card when we know its natural size; otherwise leave it to
119
- // the SDK fallback (the rule's var() defaults handle this).
120
- if (fullW > 0 && fullH > 0) {
121
- const available = window.innerHeight - drawerHeight - TOP_MARGIN;
122
- // Floor the scale so a very short panel (drawer taller than the area)
123
- // can't drive the card to 0/negative and make the deck disappear.
124
- const scale = Math.min(1, Math.max(MIN_CARD_SCALE, available / fullH));
125
- docEl.style.setProperty('--castle-logs-card-w', `${fullW * scale}px`);
126
- docEl.style.setProperty('--castle-logs-card-h', `${fullH * scale}px`);
127
- } else {
128
- docEl.style.removeProperty('--castle-logs-card-w');
129
- docEl.style.removeProperty('--castle-logs-card-h');
130
- }
131
- };
132
- apply();
133
- const observer = new ResizeObserver(apply);
134
- observer.observe(el);
135
- window.addEventListener('resize', apply);
136
- return () => {
137
- observer.disconnect();
138
- window.removeEventListener('resize', apply);
139
- delete docEl.dataset.castleLogs;
140
- docEl.style.removeProperty('--castle-logs-card-w');
141
- docEl.style.removeProperty('--castle-logs-card-h');
142
- docEl.style.removeProperty('--castle-logs-shift');
143
- };
144
70
  }, []);
145
- // Keep the newest line in view while expanded.
146
- useEffect(() => {
147
- if (open && bodyRef.current) bodyRef.current.scrollTop = bodyRef.current.scrollHeight;
148
- }, [logs, open]);
149
- const copy = useCallback(() => {
150
- const text = logs.map((line) => line.text).join('\n');
151
- navigator.clipboard?.writeText(text).catch(() => {});
152
- }, [logs]);
153
- const hasLogs = logs.length > 0;
154
71
  return (
155
- <div ref={rootRef} className={styles.playConsole}>
156
- {/* The whole header row toggles; the action buttons stopPropagation so
157
- they don't also collapse/expand. */}
158
- <div
159
- className={styles.playConsoleHeader}
160
- role="button"
161
- tabIndex={-1}
162
- aria-expanded={open}
163
- aria-label={open ? 'Collapse logs' : 'Expand logs'}
164
- onClick={() => setOpen((value) => !value)}>
165
- <span className={styles.playConsoleToggle}>
166
- <span className={styles.playConsoleCaret}>
167
- <Icon name={open ? 'chevron-down' : 'chevron-right'} />
168
- </span>
169
- <span className={styles.playConsoleTitle}>Logs</span>
170
- </span>
171
- <div
172
- className={styles.playConsoleActions}
173
- onClick={(event) => event.stopPropagation()}>
174
- {open ? (
175
- <>
176
- <button
177
- type="button"
178
- tabIndex={-1}
179
- className={styles.playConsoleBtn}
180
- aria-label="Copy logs"
181
- title="Copy logs"
182
- disabled={!hasLogs}
183
- onClick={copy}>
184
- <Icon name="clone" />
185
- </button>
186
- <button
187
- type="button"
188
- tabIndex={-1}
189
- className={styles.playConsoleBtn}
190
- aria-label="Clear logs"
191
- title="Clear logs"
192
- disabled={!hasLogs}
193
- onClick={clearLogs}>
194
- <Icon name="trash" />
195
- </button>
196
- </>
197
- ) : null}
198
- <button
199
- type="button"
200
- tabIndex={-1}
201
- className={styles.playConsoleBtn}
202
- aria-label="Restart"
203
- title="Restart"
204
- onClick={onRestart}>
205
- <Icon name="rotate" />
206
- </button>
207
- </div>
208
- </div>
209
- {open ? (
210
- <div ref={bodyRef} className={styles.playConsoleBody}>
211
- {hasLogs ? (
212
- logs.map((line) => (
213
- <div
214
- key={line.id}
215
- className={cx(
216
- styles.playConsoleLine,
217
- line.level === 'warn' && styles.playConsoleLineWarn,
218
- line.level === 'error' && styles.playConsoleLineError
219
- )}>
220
- {line.text}
221
- </div>
222
- ))
223
- ) : (
224
- <div className={styles.playConsoleEmpty}>no output</div>
225
- )}
226
- </div>
227
- ) : null}
72
+ <div style={{ position: 'fixed', inset: 0, background: '#000' }}>
73
+ <canvas
74
+ ref={canvasRef}
75
+ tabIndex={0}
76
+ style={{ width: '100%', height: '100%', display: 'block', outline: 'none' }}
77
+ />
78
+ <SceneUI getRuntime={getRuntime} />
228
79
  </div>
229
80
  );
230
81
  }
@@ -2,10 +2,13 @@ import React, { useEffect, useLayoutEffect, useRef, useState } from 'react';
2
2
  import { createPortal } from 'react-dom';
3
3
  import {
4
4
  faArrowsAlt,
5
+ faArrowsAltH,
6
+ faArrowsAltV,
5
7
  faBars,
6
8
  faChevronDown,
7
9
  faChevronRight,
8
10
  faChevronUp,
11
+ faCircle,
9
12
  faClone,
10
13
  faCode,
11
14
  faEraser,
@@ -22,6 +25,9 @@ import {
22
25
  faPlay,
23
26
  faPlus,
24
27
  faRedo,
28
+ faShapes,
29
+ faSlash,
30
+ faVectorSquare,
25
31
  faSquare,
26
32
  faStamp,
27
33
  faStop,
@@ -149,16 +155,20 @@ const icons = {
149
155
  'chevron-down': faChevronDown,
150
156
  'chevron-right': faChevronRight,
151
157
  'chevron-up': faChevronUp,
158
+ circle: faCircle,
152
159
  clone: faClone,
153
160
  code: faCode,
154
161
  eraser: faEraser,
155
162
  eyedropper: faEyeDropper,
156
163
  fill: faFillDrip,
164
+ 'flip-h': faArrowsAltH,
165
+ 'flip-v': faArrowsAltV,
157
166
  file: faFile,
158
167
  film: faFilm,
159
168
  globe: faGlobe,
160
169
  image: faImage,
161
170
  'layer-group': faLayerGroup,
171
+ marquee: faVectorSquare,
162
172
  move: faArrowsAlt,
163
173
  'object-group': faObjectGroup,
164
174
  palette: faPalette,
@@ -167,10 +177,15 @@ const icons = {
167
177
  plus: faPlus,
168
178
  redo: faRedo,
169
179
  rotate: faSyncAlt,
180
+ shapes: faShapes,
181
+ slash: faSlash,
170
182
  square: faSquare,
171
183
  stamp: faStamp,
172
184
  stop: faStop,
173
185
  times: faTimes,
186
+ // Hand-rolled equilateral-ish triangle glyph (FA free-solid has no plain
187
+ // triangle); shaped to match the filled-glyph look of the imported icons.
188
+ triangle: { icon: [512, 512, [], '', 'M256 64 L496 448 L16 448 Z'] },
174
189
  trash: faTrash,
175
190
  undo: faUndo,
176
191
  };
@@ -1158,12 +1158,21 @@
1158
1158
  flex-direction: column;
1159
1159
  width: 34px;
1160
1160
  flex: 0 0 auto;
1161
+ gap: 8px;
1162
+ }
1163
+
1164
+ /* Each control group (color, size, shape type, mode toggle) is its own boxed
1165
+ section, separated by the strip's gap. Controls stacked inside a section keep
1166
+ 1px dividers so a multi-button group still reads as one segmented unit. */
1167
+ .paintStripSection {
1168
+ display: flex;
1169
+ flex-direction: column;
1161
1170
  border: 1px solid var(--castle-inspector-border);
1162
1171
  border-radius: var(--castle-radius);
1163
1172
  overflow: hidden;
1164
1173
  }
1165
1174
 
1166
- .paintStrip > * + * {
1175
+ .paintStripSection > * + * {
1167
1176
  border-top: 1px solid var(--castle-inspector-border);
1168
1177
  }
1169
1178
 
@@ -1211,6 +1220,11 @@
1211
1220
  background: var(--castle-inspector-input-bg);
1212
1221
  }
1213
1222
 
1223
+ .paintStripModeButton:disabled {
1224
+ opacity: 0.35;
1225
+ cursor: default;
1226
+ }
1227
+
1214
1228
  .drawingSizeSliderVertical {
1215
1229
  width: 88px;
1216
1230
  height: 14px;
@@ -1292,6 +1306,21 @@
1292
1306
  justify-content: center;
1293
1307
  }
1294
1308
 
1309
+ /* Stacks the native artboard canvas and the display-resolution overlay so the
1310
+ marching-ants outline renders crisp instead of sub-pixel on the upscaled art. */
1311
+ .drawingArtboardFrame {
1312
+ position: relative;
1313
+ flex: 0 0 auto;
1314
+ }
1315
+
1316
+ .drawingOverlay {
1317
+ position: absolute;
1318
+ inset: 0;
1319
+ width: 100%;
1320
+ height: 100%;
1321
+ pointer-events: none;
1322
+ }
1323
+
1295
1324
  .drawingCanvas {
1296
1325
  image-rendering: pixelated;
1297
1326
  background:
@@ -1432,6 +1461,20 @@
1432
1461
  color: var(--castle-selected-ink);
1433
1462
  }
1434
1463
 
1464
+ /* Horizontal segmented row of shape sub-mode buttons in the wide-layout Tool
1465
+ Settings panel. Reuses .drawingToolButton glyph buttons with shared borders. */
1466
+ .drawingShapeModeRow {
1467
+ display: flex;
1468
+ width: max-content;
1469
+ border: 1px solid var(--castle-inspector-border);
1470
+ border-radius: var(--castle-radius);
1471
+ overflow: hidden;
1472
+ }
1473
+
1474
+ .drawingShapeModeRow > * + * {
1475
+ border-left: 1px solid var(--castle-inspector-border);
1476
+ }
1477
+
1435
1478
  .drawingToolHint {
1436
1479
  color: var(--castle-inspector-muted);
1437
1480
  font-size: 14px;
@@ -1902,119 +1945,3 @@
1902
1945
  }
1903
1946
  }
1904
1947
 
1905
- /* On-panel play console: a collapsible log drawer pinned to the bottom of the
1906
- play panel (portaled to <body> so it sits outside the SDK's card wrapper).
1907
- Houses the restart control plus copy/clear log affordances. */
1908
- .playConsole {
1909
- position: fixed;
1910
- left: 0;
1911
- right: 0;
1912
- bottom: 0;
1913
- z-index: 60;
1914
- display: flex;
1915
- flex-direction: column;
1916
- border-top: 1px solid rgba(255, 255, 255, 0.12);
1917
- background: rgba(13, 13, 13, 0.94);
1918
- color: #e6e6e6;
1919
- font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono',
1920
- 'Courier New', monospace;
1921
- padding-bottom: env(safe-area-inset-bottom, 0px);
1922
- overflow: hidden;
1923
- }
1924
- .playConsoleHeader {
1925
- display: flex;
1926
- align-items: center;
1927
- justify-content: space-between;
1928
- gap: 8px;
1929
- padding: 7px 8px 7px 10px;
1930
- cursor: pointer;
1931
- }
1932
- .playConsoleHeader:hover {
1933
- background: rgba(255, 255, 255, 0.04);
1934
- }
1935
- .playConsoleToggle {
1936
- display: flex;
1937
- align-items: center;
1938
- gap: 8px;
1939
- }
1940
- .playConsoleCaret {
1941
- display: inline-flex;
1942
- font-size: 11px;
1943
- color: #8a8a8a;
1944
- }
1945
- .playConsoleTitle {
1946
- font-size: 11px;
1947
- font-weight: 700;
1948
- letter-spacing: 1px;
1949
- text-transform: uppercase;
1950
- color: #b3b3b3;
1951
- }
1952
- .playConsoleActions {
1953
- display: flex;
1954
- align-items: center;
1955
- gap: 6px;
1956
- }
1957
- .playConsoleBtn {
1958
- display: inline-flex;
1959
- align-items: center;
1960
- justify-content: center;
1961
- width: 30px;
1962
- height: 28px;
1963
- padding: 0;
1964
- font-size: 13px;
1965
- color: #cfcfcf;
1966
- background: transparent;
1967
- border: 1px solid rgba(255, 255, 255, 0.14);
1968
- border-radius: 6px;
1969
- cursor: pointer;
1970
- }
1971
- .playConsoleBtn:hover {
1972
- background: rgba(255, 255, 255, 0.08);
1973
- color: #fff;
1974
- }
1975
- .playConsoleBtn:disabled {
1976
- opacity: 0.38;
1977
- cursor: default;
1978
- }
1979
- .playConsoleBtn:disabled:hover {
1980
- background: transparent;
1981
- color: #cfcfcf;
1982
- }
1983
- .playConsoleBody {
1984
- border-top: 1px solid rgba(255, 255, 255, 0.08);
1985
- height: 165px;
1986
- overflow-y: auto;
1987
- padding: 8px 10px;
1988
- font-size: 12px;
1989
- line-height: 1.5;
1990
- }
1991
- .playConsoleEmpty {
1992
- color: #6a6a6a;
1993
- }
1994
- .playConsoleLine {
1995
- white-space: pre-wrap;
1996
- word-break: break-word;
1997
- color: #c8c8c8;
1998
- }
1999
- .playConsoleLineWarn {
2000
- color: #e0af68;
2001
- }
2002
- .playConsoleLineError {
2003
- color: #ff7a93;
2004
- }
2005
-
2006
- /* While the logs drawer is mounted, scale the deck card to fit ABOVE the drawer
2007
- (rather than sitting behind it) so play stays fully visible and interactive.
2008
- The SDK's initPlayCard() pins `#root > *` as a viewport-centered card with
2009
- !important; this higher-specificity (attribute + id) rule overrides its size
2010
- and vertical offset. The three custom properties are driven from JS in
2011
- PlayConsole using the live drawer height + the SDK's natural card size. */
2012
- :global(html[data-castle-logs] #root > *) {
2013
- width: var(--castle-logs-card-w, var(--castle-card-w, 100vw)) !important;
2014
- height: var(--castle-logs-card-h, var(--castle-card-h, 100vh)) !important;
2015
- transform: translate(-50%, calc(-50% - var(--castle-logs-shift, 0px))) !important;
2016
- transition:
2017
- transform 0.18s ease,
2018
- width 0.18s ease,
2019
- height 0.18s ease;
2020
- }
@@ -1,27 +1,23 @@
1
1
  import React from 'react';
2
2
  import { createRoot } from 'react-dom/client';
3
3
  import { isEdit, setup } from 'castle-web-sdk';
4
- import { App } from './editors/App';
5
4
  import { PlayOnly } from './editors/PlayOnly';
6
5
  import { ErrorBoundary } from './editors/ErrorBoundary';
7
- import { FileList, SingleEditor } from './editors/SingleEditor';
6
+ import { SingleEditor } from './editors/SingleEditor';
8
7
  document.body.dataset.castleScreenshotTarget = 'viewport';
9
8
  setup();
10
9
  const root = document.getElementById('root');
11
10
  if (!root) throw new Error('Missing root element');
12
- // Route on URL params so the shell can mount each piece in its own panel iframe:
11
+ // Route on URL params so the shell can mount each piece in its own panel iframe.
12
+ // File browsing and the code/text editor are now builtin shell panels, so the
13
+ // kit only renders the deck (play) and its rich per-file editors (scene/pxart):
13
14
  // (no edit / ?edit=0) -> play the deck (playtest panel)
14
- // ?panel=files -> the file list (asks the shell to open files)
15
- // ?file=<path>[&editor=<id>] -> a single editor for that file
16
- // (edit, no params) -> the combined editor app (legacy fallback)
15
+ // ?file=<path>[&editor=<id>] -> a single rich editor for that file
17
16
  const params = new URLSearchParams(window.location.search);
18
17
  function pick() {
19
18
  if (!isEdit()) return <PlayOnly />;
20
- if (params.get('panel') === 'files') {
21
- return <FileList selectedPath={params.get('file') ?? ''} />;
22
- }
23
19
  const file = params.get('file');
24
20
  if (file) return <SingleEditor path={file} editor={params.get('editor') ?? undefined} />;
25
- return <App />;
21
+ return <PlayOnly />;
26
22
  }
27
23
  createRoot(root).render(<ErrorBoundary>{pick()}</ErrorBoundary>);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "castle-web-cli",
3
- "version": "0.4.75",
3
+ "version": "0.4.76",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "castle-web": "./dist/index.js"
@@ -23,15 +23,23 @@
23
23
  ]
24
24
  },
25
25
  "dependencies": {
26
+ "@codemirror/lang-javascript": "^6.2.5",
27
+ "@codemirror/language": "^6.12.3",
28
+ "@codemirror/state": "^6.6.0",
29
+ "@codemirror/view": "^6.41.1",
30
+ "@fortawesome/free-solid-svg-icons": "^5.15.4",
31
+ "@lezer/highlight": "^1.2.3",
26
32
  "@lydell/node-pty": "^1.2.0-beta.12",
27
33
  "@xterm/addon-fit": "^0.11.0",
28
34
  "@xterm/addon-serialize": "^0.14.0",
29
35
  "@xterm/headless": "^6.0.0",
30
36
  "@xterm/xterm": "^6.0.0",
37
+ "codemirror": "^6.0.2",
31
38
  "dockview": "^4.13.1",
32
39
  "marked": "^18.0.5",
33
40
  "nanoid": "^5.1.7",
34
41
  "open": "^10.0.0",
42
+ "picomatch": "^4.0.4",
35
43
  "react": "^18.3.1",
36
44
  "react-dom": "^18.3.1",
37
45
  "vite": "^8.0.3",
@@ -40,6 +48,7 @@
40
48
  },
41
49
  "devDependencies": {
42
50
  "@types/node": "^20.0.0",
51
+ "@types/picomatch": "^4.0.2",
43
52
  "@types/react": "^18.3.31",
44
53
  "@types/react-dom": "^18.3.7",
45
54
  "@types/ws": "^8.18.1",