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.
- package/dist/agent-prompts.d.ts +4 -0
- package/dist/agent-prompts.js +20 -8
- package/dist/agent.js +301 -28
- package/dist/castle-host/host.js +59 -5
- package/dist/commonInstructions.d.ts +1 -1
- package/dist/commonInstructions.js +4 -0
- package/dist/ide.d.ts +1 -0
- package/dist/ide.js +250 -1
- package/dist/init.js +46 -4
- package/dist/save-deck.js +8 -1
- package/dist/serve.js +27 -1
- package/dist/shell/assets/index-DNWEQd4R.js +141 -0
- package/dist/shell/assets/{index-WNbOHPBj.css → index-DuKq-Grp.css} +1 -1
- package/dist/shell/index.html +2 -2
- package/kits/basic-2d/CLAUDE.md +13 -5
- package/kits/basic-2d/castle.json +15 -0
- package/kits/basic-2d/drawings/pig.pxart +22 -55
- package/kits/basic-2d/editors/PxArtEditor.jsx +237 -4
- package/kits/basic-2d/editors/SingleEditor.jsx +6 -51
- package/kits/basic-2d/editors/pixelEditorChrome.jsx +17 -11
- package/kits/basic-2d/editors/pixelGeometry.js +95 -0
- package/kits/basic-2d/editors/pixelInspector.jsx +229 -51
- package/kits/basic-2d/editors/pxArtTools.js +109 -1
- package/kits/basic-2d/engine/ScenePlayer.jsx +11 -160
- package/kits/basic-2d/engine/ui.jsx +15 -0
- package/kits/basic-2d/engine/ui.module.css +44 -117
- package/kits/basic-2d/main.jsx +6 -10
- package/package.json +10 -1
- package/dist/shell/assets/index-Dfn29Bkt.js +0 -108
- package/kits/basic-2d/editors/App.jsx +0 -226
- package/kits/basic-2d/editors/CodeEditor.jsx +0 -79
- package/kits/basic-2d/editors/FileBrowser.jsx +0 -349
- package/kits/basic-2d/editors/codeTheme.js +0 -135
- package/kits/basic-2d/engine/playConsole.js +0 -66
- package/kits/basic-3d/.prettierrc +0 -8
- package/kits/basic-3d/CLAUDE.md +0 -162
- package/kits/basic-3d/behaviors/Camera.jsx +0 -56
- package/kits/basic-3d/behaviors/Collider.jsx +0 -78
- package/kits/basic-3d/behaviors/Mesh.jsx +0 -82
- package/kits/basic-3d/behaviors/Model.jsx +0 -61
- package/kits/basic-3d/behaviors/Transform.jsx +0 -35
- package/kits/basic-3d/editors/App.jsx +0 -147
- package/kits/basic-3d/editors/CodeEditor.jsx +0 -112
- package/kits/basic-3d/editors/FileBrowser.jsx +0 -143
- package/kits/basic-3d/editors/ModelEditor.jsx +0 -400
- package/kits/basic-3d/editors/PlayOnly.jsx +0 -22
- package/kits/basic-3d/editors/SceneEditor.jsx +0 -1081
- package/kits/basic-3d/editors/behaviorRegistry.js +0 -24
- package/kits/basic-3d/editors/editorHistory.js +0 -52
- package/kits/basic-3d/editors/viewportRig.js +0 -90
- package/kits/basic-3d/engine/ScenePlayer.jsx +0 -58
- package/kits/basic-3d/engine/SceneUI.jsx +0 -67
- package/kits/basic-3d/engine/SceneViewport.jsx +0 -102
- package/kits/basic-3d/engine/autoInspector.jsx +0 -51
- package/kits/basic-3d/engine/files.js +0 -73
- package/kits/basic-3d/engine/scene.js +0 -502
- package/kits/basic-3d/engine/threeUtil.js +0 -260
- package/kits/basic-3d/engine/ui.jsx +0 -352
- package/kits/basic-3d/engine/ui.module.css +0 -944
- package/kits/basic-3d/eslint.config.js +0 -51
- package/kits/basic-3d/index.html +0 -11
- package/kits/basic-3d/main.jsx +0 -10
- package/kits/basic-3d/models/block.model +0 -14
- package/kits/basic-3d/package-lock.json +0 -2713
- package/kits/basic-3d/package.json +0 -41
- package/kits/basic-3d/pnpm-lock.yaml +0 -1769
- package/kits/basic-3d/scenes/main.scene +0 -76
- package/kits/basic-3d/vite.config.js +0 -1
|
@@ -1,21 +1,15 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useRef
|
|
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
|
-
|
|
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
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
-
.
|
|
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
|
-
}
|
package/kits/basic-2d/main.jsx
CHANGED
|
@@ -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 {
|
|
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
|
-
// ?
|
|
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 <
|
|
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.
|
|
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",
|