castle-web-cli 0.4.3 → 0.4.5

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 (97) hide show
  1. package/dist/index.js +8 -2
  2. package/dist/init.js +1 -1
  3. package/kits/basic-2d/CLAUDE.md +3 -3
  4. package/package.json +1 -1
  5. package/kits/basic-2d-frozen/.prettierrc +0 -8
  6. package/kits/basic-2d-frozen/CLAUDE.md +0 -131
  7. package/kits/basic-2d-frozen/behaviors/Camera.jsx +0 -43
  8. package/kits/basic-2d-frozen/behaviors/Collider.jsx +0 -71
  9. package/kits/basic-2d-frozen/behaviors/Drawing.jsx +0 -139
  10. package/kits/basic-2d-frozen/behaviors/Layout.jsx +0 -16
  11. package/kits/basic-2d-frozen/drawings/floor.drawing +0 -70
  12. package/kits/basic-2d-frozen/editors/App.jsx +0 -152
  13. package/kits/basic-2d-frozen/editors/CodeEditor.jsx +0 -112
  14. package/kits/basic-2d-frozen/editors/DrawingEditor.jsx +0 -222
  15. package/kits/basic-2d-frozen/editors/FileBrowser.jsx +0 -143
  16. package/kits/basic-2d-frozen/editors/PlayOnly.jsx +0 -21
  17. package/kits/basic-2d-frozen/editors/SceneEditor.jsx +0 -1012
  18. package/kits/basic-2d-frozen/editors/behaviorRegistry.js +0 -24
  19. package/kits/basic-2d-frozen/editors/editorHistory.js +0 -52
  20. package/kits/basic-2d-frozen/engine/ScenePlayer.jsx +0 -83
  21. package/kits/basic-2d-frozen/engine/SceneUI.jsx +0 -67
  22. package/kits/basic-2d-frozen/engine/TouchControls.jsx +0 -136
  23. package/kits/basic-2d-frozen/engine/autoInspector.jsx +0 -51
  24. package/kits/basic-2d-frozen/engine/files.js +0 -62
  25. package/kits/basic-2d-frozen/engine/scene.js +0 -420
  26. package/kits/basic-2d-frozen/engine/ui.jsx +0 -344
  27. package/kits/basic-2d-frozen/engine/ui.module.css +0 -928
  28. package/kits/basic-2d-frozen/eslint.config.js +0 -50
  29. package/kits/basic-2d-frozen/index.html +0 -11
  30. package/kits/basic-2d-frozen/main.jsx +0 -10
  31. package/kits/basic-2d-frozen/package-lock.json +0 -2706
  32. package/kits/basic-2d-frozen/package.json +0 -41
  33. package/kits/basic-2d-frozen/scenes/main.scene +0 -108
  34. package/kits/basic-2d-frozen/vite.config.js +0 -1
  35. package/kits/rpg-2d/.prettierrc +0 -8
  36. package/kits/rpg-2d/behaviors/Camera.tsx +0 -52
  37. package/kits/rpg-2d/behaviors/Collider.tsx +0 -98
  38. package/kits/rpg-2d/behaviors/Dialog.tsx +0 -184
  39. package/kits/rpg-2d/behaviors/Drawing.tsx +0 -161
  40. package/kits/rpg-2d/behaviors/Friend.tsx +0 -45
  41. package/kits/rpg-2d/behaviors/Layout.tsx +0 -29
  42. package/kits/rpg-2d/behaviors/PlayerController.tsx +0 -255
  43. package/kits/rpg-2d/behaviors/Portal.tsx +0 -60
  44. package/kits/rpg-2d/behaviors/QuestLog.tsx +0 -90
  45. package/kits/rpg-2d/behaviors/SaveMenu.tsx +0 -123
  46. package/kits/rpg-2d/behaviors/Tilemap.tsx +0 -90
  47. package/kits/rpg-2d/drawings/bld-home.drawing +0 -8136
  48. package/kits/rpg-2d/drawings/env-crate.drawing +0 -509
  49. package/kits/rpg-2d/drawings/env-fence.drawing +0 -536
  50. package/kits/rpg-2d/drawings/env-flower-bed.drawing +0 -607
  51. package/kits/rpg-2d/drawings/env-fountain.drawing +0 -2622
  52. package/kits/rpg-2d/drawings/env-hedge.drawing +0 -601
  53. package/kits/rpg-2d/drawings/env-house-blue.drawing +0 -1
  54. package/kits/rpg-2d/drawings/env-house-green.drawing +0 -1
  55. package/kits/rpg-2d/drawings/env-tree-oak.drawing +0 -1540
  56. package/kits/rpg-2d/drawings/env-tree-pine.drawing +0 -1315
  57. package/kits/rpg-2d/drawings/floor.drawing +0 -70
  58. package/kits/rpg-2d/drawings/fx-sparkle.drawing +0 -926
  59. package/kits/rpg-2d/drawings/npc-juno-idle-down.drawing +0 -1099
  60. package/kits/rpg-2d/drawings/npc-juno-walk-down.drawing +0 -4177
  61. package/kits/rpg-2d/drawings/npc-opal-idle-down.drawing +0 -1099
  62. package/kits/rpg-2d/drawings/npc-opal-walk-down.drawing +0 -4177
  63. package/kits/rpg-2d/drawings/player-idle-down.drawing +0 -1070
  64. package/kits/rpg-2d/drawings/player-idle-left.drawing +0 -1070
  65. package/kits/rpg-2d/drawings/player-idle-right.drawing +0 -1070
  66. package/kits/rpg-2d/drawings/player-idle-up.drawing +0 -1070
  67. package/kits/rpg-2d/drawings/player-walk-down.drawing +0 -4148
  68. package/kits/rpg-2d/drawings/player-walk-left.drawing +0 -4148
  69. package/kits/rpg-2d/drawings/player-walk-right.drawing +0 -4148
  70. package/kits/rpg-2d/drawings/player-walk-up.drawing +0 -4148
  71. package/kits/rpg-2d/editors/App.tsx +0 -163
  72. package/kits/rpg-2d/editors/CodeEditor.tsx +0 -120
  73. package/kits/rpg-2d/editors/DrawingEditor.tsx +0 -278
  74. package/kits/rpg-2d/editors/FileBrowser.tsx +0 -191
  75. package/kits/rpg-2d/editors/PlayOnly.tsx +0 -26
  76. package/kits/rpg-2d/editors/SceneEditor.tsx +0 -1093
  77. package/kits/rpg-2d/editors/behaviorRegistry.ts +0 -33
  78. package/kits/rpg-2d/editors/editorHistory.ts +0 -75
  79. package/kits/rpg-2d/editors/editorProps.ts +0 -10
  80. package/kits/rpg-2d/engine/ScenePlayer.tsx +0 -130
  81. package/kits/rpg-2d/engine/SceneUI.tsx +0 -74
  82. package/kits/rpg-2d/engine/TouchControls.tsx +0 -157
  83. package/kits/rpg-2d/engine/autoInspector.tsx +0 -111
  84. package/kits/rpg-2d/engine/drawing.ts +0 -81
  85. package/kits/rpg-2d/engine/files.ts +0 -215
  86. package/kits/rpg-2d/engine/scene.ts +0 -484
  87. package/kits/rpg-2d/engine/ui.module.css +0 -928
  88. package/kits/rpg-2d/engine/ui.tsx +0 -483
  89. package/kits/rpg-2d/eslint.config.js +0 -46
  90. package/kits/rpg-2d/index.html +0 -11
  91. package/kits/rpg-2d/main.tsx +0 -14
  92. package/kits/rpg-2d/package-lock.json +0 -3149
  93. package/kits/rpg-2d/package.json +0 -46
  94. package/kits/rpg-2d/scenes/main.scene +0 -203
  95. package/kits/rpg-2d/tsconfig.json +0 -17
  96. package/kits/rpg-2d/vite-env.d.ts +0 -7
  97. package/kits/rpg-2d/vite.config.js +0 -1
@@ -1,420 +0,0 @@
1
- const CARD_WIDTH = 500;
2
- const CARD_HEIGHT = 700;
3
-
4
- export const cardSize = { width: CARD_WIDTH, height: CARD_HEIGHT };
5
-
6
- export class SceneRuntime {
7
- constructor(sceneData, behaviors, drawings) {
8
- this.behaviors = new Map(behaviors.map((Behavior) => [Behavior.behaviorName, Behavior]));
9
- this.drawings = drawings;
10
- this.time = 0;
11
- this.keys = new Set();
12
- this.pointer = { x: 0, y: 0, down: false };
13
- this.data = { actors: [] };
14
- this.actors = new Map();
15
- this.camera = undefined;
16
- this.status = undefined;
17
- this.load(sceneData);
18
- }
19
-
20
- load(sceneData) {
21
- this.data = structuredClone(sceneData);
22
- this.actors = new Map();
23
- for (const actor of this.data.actors ?? []) {
24
- actor.runtime = {};
25
- this.actors.set(actor.id, actor);
26
- for (const [behaviorName, Behavior] of this.behaviors) {
27
- const component = actor.components[behaviorName];
28
- if (component) {
29
- actor.components[behaviorName] = {
30
- ...Behavior.defaultProps,
31
- ...component,
32
- };
33
- }
34
- }
35
- }
36
- }
37
-
38
- clone() {
39
- return new SceneRuntime(this.serialize(), [...this.behaviors.values()], this.drawings);
40
- }
41
-
42
- serialize() {
43
- return structuredClone(this.data);
44
- }
45
-
46
- getActor(actorId) {
47
- return this.actors.get(actorId);
48
- }
49
-
50
- getActors() {
51
- return [...this.actors.values()].sort((a, b) => {
52
- const az = getLayout(a)?.z ?? 0;
53
- const bz = getLayout(b)?.z ?? 0;
54
- return az - bz;
55
- });
56
- }
57
-
58
- getComponent(actor, behaviorName) {
59
- return actor?.components?.[behaviorName] ?? null;
60
- }
61
-
62
- actorWith(behaviorName) {
63
- for (const actor of this.actors.values()) {
64
- if (actor.components?.[behaviorName]) return actor;
65
- }
66
- return null;
67
- }
68
-
69
- actorsWith(behaviorName) {
70
- const out = [];
71
- for (const actor of this.getActors()) {
72
- if (actor.components?.[behaviorName]) out.push(actor);
73
- }
74
- return out;
75
- }
76
-
77
- colliderRect(actorOrId) {
78
- const actor = typeof actorOrId === 'string' ? this.getActor(actorOrId) : actorOrId;
79
- return getColliderRect(actor);
80
- }
81
-
82
- overlaps(first, second) {
83
- const a = this.colliderRect(first);
84
- const b = this.colliderRect(second);
85
- return Boolean(a && b && intersects(a, b));
86
- }
87
-
88
- spawnActor(actor) {
89
- const id = actor.id ?? mintActorId(new Set(this.actors.keys()));
90
- const components = {};
91
- for (const [name, props] of Object.entries(actor.components ?? {})) {
92
- const Behavior = this.behaviors.get(name);
93
- components[name] = Behavior ? { ...Behavior.defaultProps, ...props } : { ...props };
94
- }
95
- const next = { ...actor, id, components, runtime: {} };
96
- this.data.actors.push(next);
97
- this.actors.set(id, next);
98
- return next;
99
- }
100
-
101
- despawnActor(actorId) {
102
- const actor = this.actors.get(actorId);
103
- if (!actor) return false;
104
- this.actors.delete(actorId);
105
- const idx = this.data.actors.findIndex((a) => a.id === actorId);
106
- if (idx !== -1) this.data.actors.splice(idx, 1);
107
- return true;
108
- }
109
-
110
- // Translate a screen-space pointer event into the scene's world-space
111
- // `pointer`. The runtime owns this mapping (it knows the camera) so every
112
- // input path -- the standalone ScenePlayer and the editor's play mode --
113
- // agree on it; behaviors read `scene.pointer` in world coordinates. Pass
114
- // `down` to also update the press state.
115
- setPointerFromScreen(canvas, clientX, clientY, down) {
116
- const point = screenToCard(canvas, clientX, clientY);
117
- this.pointer.x = point.x + (this.camera?.x ?? 0);
118
- this.pointer.y = point.y + (this.camera?.y ?? 0);
119
- if (down !== undefined) this.pointer.down = down;
120
- }
121
-
122
- update(dt) {
123
- this.time += dt;
124
- for (const actor of this.getActors()) {
125
- this.forEachBehavior(actor, (instance) => instance.update?.(actor, this, dt));
126
- }
127
- }
128
-
129
- forEachBehavior(actor, callback) {
130
- for (const [behaviorName, props] of Object.entries(actor.components)) {
131
- if (!props) continue;
132
- const Behavior = this.behaviors.get(behaviorName);
133
- if (!Behavior) continue;
134
- callback(new Behavior(props));
135
- }
136
- }
137
-
138
- draw(ctx, options = {}) {
139
- ctx.clearRect(0, 0, CARD_WIDTH, CARD_HEIGHT);
140
- ctx.fillStyle = this.data.background ?? '#0f2a1d';
141
- ctx.fillRect(0, 0, CARD_WIDTH, CARD_HEIGHT);
142
-
143
- ctx.save();
144
- if (options.useCamera && this.camera) {
145
- ctx.translate(-Math.round(this.camera.x ?? 0), -Math.round(this.camera.y ?? 0));
146
- }
147
- for (const actor of this.getActors()) {
148
- // Per-actor transform: Layout's `rotation` (degrees) rotates every draw
149
- // behavior of the actor about its center.
150
- ctx.save();
151
- applyLayoutRotation(ctx, getLayout(actor));
152
- if (options.editPlaceholders) drawEditPlaceholder(ctx, actor);
153
- this.forEachBehavior(actor, (instance) => instance.draw?.(actor, this, ctx, options));
154
- ctx.restore();
155
- }
156
-
157
- if (options.showGrid) drawGrid(ctx);
158
- if (options.selectedActorIds) {
159
- for (const id of options.selectedActorIds) {
160
- const actor = this.getActor(id);
161
- if (actor) drawSelection(ctx, actor);
162
- }
163
- }
164
- if (options.marquee) drawMarquee(ctx, options.marquee);
165
- ctx.restore();
166
- }
167
-
168
- actorAt(x, y) {
169
- const actors = this.getActors().slice().reverse();
170
- for (const actor of actors) {
171
- const layout = getLayout(actor);
172
- if (!layout) continue;
173
- if (
174
- x >= layout.x &&
175
- x <= layout.x + layout.width &&
176
- y >= layout.y &&
177
- y <= layout.y + layout.height
178
- ) {
179
- return actor;
180
- }
181
- }
182
- return null;
183
- }
184
-
185
- actorIdsInRect(rect) {
186
- const minX = rect.x;
187
- const minY = rect.y;
188
- const maxX = rect.x + rect.width;
189
- const maxY = rect.y + rect.height;
190
- const ids = [];
191
- for (const actor of this.getActors()) {
192
- const layout = getLayout(actor);
193
- if (!layout) continue;
194
- if (
195
- layout.x + layout.width >= minX &&
196
- layout.x <= maxX &&
197
- layout.y + layout.height >= minY &&
198
- layout.y <= maxY
199
- ) {
200
- ids.push(actor.id);
201
- }
202
- }
203
- return ids;
204
- }
205
- }
206
-
207
- export function makeScene(sceneData, behaviors, drawings) {
208
- return new SceneRuntime(sceneData, behaviors, drawings);
209
- }
210
-
211
- export function setActorComponent(sceneData, actorId, behaviorName, nextProps) {
212
- const next = structuredClone(sceneData);
213
- const actor = next.actors.find((candidate) => candidate.id === actorId);
214
- if (!actor) return sceneData;
215
- actor.components[behaviorName] = {
216
- ...(actor.components[behaviorName] ?? {}),
217
- ...nextProps,
218
- };
219
- return next;
220
- }
221
-
222
- export function removeActorComponent(sceneData, actorId, behaviorName) {
223
- const next = structuredClone(sceneData);
224
- const actor = next.actors.find((candidate) => candidate.id === actorId);
225
- if (!actor || !(behaviorName in actor.components)) return sceneData;
226
- delete actor.components[behaviorName];
227
- return next;
228
- }
229
-
230
- export function moveActors(sceneData, actorIds, dx, dy) {
231
- if (actorIds.length === 0) return sceneData;
232
- const next = structuredClone(sceneData);
233
- let changed = false;
234
- for (const id of actorIds) {
235
- const actor = next.actors.find((candidate) => candidate.id === id);
236
- const layout = actor ? actor.components.Layout : null;
237
- if (!actor || !layout) continue;
238
- actor.components.Layout = {
239
- ...layout,
240
- x: Math.round(layout.x + dx),
241
- y: Math.round(layout.y + dy),
242
- };
243
- changed = true;
244
- }
245
- return changed ? next : sceneData;
246
- }
247
-
248
- export function removeActors(sceneData, actorIds) {
249
- if (actorIds.length === 0) return sceneData;
250
- const toRemove = new Set(actorIds);
251
- const next = structuredClone(sceneData);
252
- next.actors = next.actors.filter((actor) => !toRemove.has(actor.id));
253
- return next.actors.length === sceneData.actors.length ? sceneData : next;
254
- }
255
-
256
- export function duplicateActors(sceneData, actorIds) {
257
- if (actorIds.length === 0) return { sceneData, newIds: [] };
258
- const next = structuredClone(sceneData);
259
- const existingIds = new Set(next.actors.map((actor) => actor.id));
260
- const newIds = [];
261
- for (const id of actorIds) {
262
- const source = next.actors.find((candidate) => candidate.id === id);
263
- if (!source) continue;
264
- const copy = structuredClone(source);
265
- copy.id = mintActorId(existingIds);
266
- existingIds.add(copy.id);
267
- const layout = copy.components.Layout;
268
- if (layout) {
269
- copy.components.Layout = {
270
- ...layout,
271
- x: Math.round(layout.x + 1),
272
- y: Math.round(layout.y + 1),
273
- };
274
- }
275
- next.actors.push(copy);
276
- newIds.push(copy.id);
277
- }
278
- return { sceneData: next, newIds };
279
- }
280
-
281
- export function addActor(sceneData, _files, drawings) {
282
- const next = structuredClone(sceneData);
283
- const existingIds = new Set(next.actors.map((actor) => actor.id));
284
- const id = mintActorId(existingIds);
285
- const width = 64;
286
- const height = 64;
287
- const layout = {
288
- x: Math.round((CARD_WIDTH - width) / 2),
289
- y: Math.round((CARD_HEIGHT - height) / 2),
290
- width,
291
- height,
292
- z: 0,
293
- rotation: 0,
294
- };
295
- const components = { Layout: layout };
296
- const drawingPath = Object.keys(drawings).sort()[0];
297
- if (drawingPath) {
298
- components.Drawing = { file: drawingPath };
299
- }
300
- next.actors.push({ id, components });
301
- return { sceneData: next, newId: id };
302
- }
303
-
304
- function mintActorId(existing) {
305
- for (let attempt = 0; attempt < 64; attempt++) {
306
- const candidate = Math.floor(Math.random() * 0xffffffff)
307
- .toString(16)
308
- .padStart(8, '0');
309
- if (!existing.has(candidate)) return candidate;
310
- }
311
- return `${Date.now().toString(16)}${Math.floor(Math.random() * 0xffff).toString(16)}`;
312
- }
313
-
314
- export function screenToCard(canvas, clientX, clientY) {
315
- const rect = canvas.getBoundingClientRect();
316
- return {
317
- x: ((clientX - rect.left) / rect.width) * CARD_WIDTH,
318
- y: ((clientY - rect.top) / rect.height) * CARD_HEIGHT,
319
- };
320
- }
321
-
322
- export function configureSceneCanvas(canvas, ctx = canvas.getContext('2d')) {
323
- if (!ctx) return null;
324
- const rect = canvas.getBoundingClientRect();
325
- const dpr = window.devicePixelRatio || 1;
326
- const displayWidth = rect.width || CARD_WIDTH;
327
- const displayHeight = rect.height || CARD_HEIGHT;
328
- const pixelWidth = Math.max(1, Math.round(displayWidth * dpr));
329
- const pixelHeight = Math.max(1, Math.round(displayHeight * dpr));
330
- if (canvas.width !== pixelWidth) canvas.width = pixelWidth;
331
- if (canvas.height !== pixelHeight) canvas.height = pixelHeight;
332
- ctx.setTransform(pixelWidth / CARD_WIDTH, 0, 0, pixelHeight / CARD_HEIGHT, 0, 0);
333
- ctx.imageSmoothingEnabled = true;
334
- return ctx;
335
- }
336
-
337
- function drawGrid(ctx) {
338
- ctx.save();
339
- ctx.strokeStyle = 'rgba(255, 255, 255, 0.08)';
340
- ctx.lineWidth = 1;
341
- for (let x = 0; x <= CARD_WIDTH; x += 25) {
342
- ctx.beginPath();
343
- ctx.moveTo(x + 0.5, 0);
344
- ctx.lineTo(x + 0.5, CARD_HEIGHT);
345
- ctx.stroke();
346
- }
347
- for (let y = 0; y <= CARD_HEIGHT; y += 25) {
348
- ctx.beginPath();
349
- ctx.moveTo(0, y + 0.5);
350
- ctx.lineTo(CARD_WIDTH, y + 0.5);
351
- ctx.stroke();
352
- }
353
- ctx.restore();
354
- }
355
-
356
- function drawEditPlaceholder(ctx, actor) {
357
- const layout = getLayout(actor);
358
- if (!layout) return;
359
- ctx.save();
360
- ctx.fillStyle = 'rgba(255, 255, 255, 0.04)';
361
- ctx.fillRect(layout.x, layout.y, layout.width, layout.height);
362
- ctx.strokeStyle = 'rgba(255, 255, 255, 0.25)';
363
- ctx.lineWidth = 1;
364
- ctx.strokeRect(layout.x + 0.5, layout.y + 0.5, layout.width - 1, layout.height - 1);
365
- ctx.restore();
366
- }
367
-
368
- function drawMarquee(ctx, rect) {
369
- if (rect.width === 0 || rect.height === 0) return;
370
- ctx.save();
371
- ctx.fillStyle = 'rgba(255, 255, 255, 0.12)';
372
- ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
373
- ctx.strokeStyle = 'rgba(255, 255, 255, 0.85)';
374
- ctx.lineWidth = 1;
375
- ctx.setLineDash([4, 3]);
376
- ctx.strokeRect(rect.x + 0.5, rect.y + 0.5, rect.width - 1, rect.height - 1);
377
- ctx.restore();
378
- }
379
-
380
- function drawSelection(ctx, actor) {
381
- const layout = getLayout(actor);
382
- if (!layout) return;
383
- ctx.save();
384
- applyLayoutRotation(ctx, layout);
385
- ctx.strokeStyle = '#fff';
386
- ctx.lineWidth = 2;
387
- ctx.setLineDash([6, 4]);
388
- ctx.strokeRect(layout.x + 1, layout.y + 1, layout.width - 2, layout.height - 2);
389
- ctx.restore();
390
- }
391
-
392
- function applyLayoutRotation(ctx, layout) {
393
- const rotation = layout?.rotation ?? 0;
394
- if (!rotation || !layout) return;
395
- const cx = layout.x + layout.width / 2;
396
- const cy = layout.y + layout.height / 2;
397
- ctx.translate(cx, cy);
398
- ctx.rotate((rotation * Math.PI) / 180);
399
- ctx.translate(-cx, -cy);
400
- }
401
-
402
- function getLayout(actor) {
403
- return actor?.components?.Layout;
404
- }
405
-
406
- function getColliderRect(actor) {
407
- const layout = getLayout(actor);
408
- const collider = actor?.components?.Collider;
409
- if (!layout || !collider) return null;
410
- return {
411
- x: layout.x + (collider.offsetX ?? 0),
412
- y: layout.y + (collider.offsetY ?? 0),
413
- width: collider.width ?? layout.width,
414
- height: collider.height ?? layout.height,
415
- };
416
- }
417
-
418
- function intersects(a, b) {
419
- return a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y;
420
- }