castle-web-cli 0.4.2 → 0.4.4

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 (96) hide show
  1. package/dist/index.js +8 -2
  2. package/dist/init.js +9 -6
  3. package/package.json +1 -1
  4. package/kits/basic-2d-frozen/.prettierrc +0 -8
  5. package/kits/basic-2d-frozen/CLAUDE.md +0 -131
  6. package/kits/basic-2d-frozen/behaviors/Camera.jsx +0 -43
  7. package/kits/basic-2d-frozen/behaviors/Collider.jsx +0 -71
  8. package/kits/basic-2d-frozen/behaviors/Drawing.jsx +0 -139
  9. package/kits/basic-2d-frozen/behaviors/Layout.jsx +0 -16
  10. package/kits/basic-2d-frozen/drawings/floor.drawing +0 -70
  11. package/kits/basic-2d-frozen/editors/App.jsx +0 -152
  12. package/kits/basic-2d-frozen/editors/CodeEditor.jsx +0 -112
  13. package/kits/basic-2d-frozen/editors/DrawingEditor.jsx +0 -222
  14. package/kits/basic-2d-frozen/editors/FileBrowser.jsx +0 -143
  15. package/kits/basic-2d-frozen/editors/PlayOnly.jsx +0 -21
  16. package/kits/basic-2d-frozen/editors/SceneEditor.jsx +0 -1012
  17. package/kits/basic-2d-frozen/editors/behaviorRegistry.js +0 -24
  18. package/kits/basic-2d-frozen/editors/editorHistory.js +0 -52
  19. package/kits/basic-2d-frozen/engine/ScenePlayer.jsx +0 -83
  20. package/kits/basic-2d-frozen/engine/SceneUI.jsx +0 -67
  21. package/kits/basic-2d-frozen/engine/TouchControls.jsx +0 -136
  22. package/kits/basic-2d-frozen/engine/autoInspector.jsx +0 -51
  23. package/kits/basic-2d-frozen/engine/files.js +0 -62
  24. package/kits/basic-2d-frozen/engine/scene.js +0 -420
  25. package/kits/basic-2d-frozen/engine/ui.jsx +0 -344
  26. package/kits/basic-2d-frozen/engine/ui.module.css +0 -928
  27. package/kits/basic-2d-frozen/eslint.config.js +0 -50
  28. package/kits/basic-2d-frozen/index.html +0 -11
  29. package/kits/basic-2d-frozen/main.jsx +0 -10
  30. package/kits/basic-2d-frozen/package-lock.json +0 -2706
  31. package/kits/basic-2d-frozen/package.json +0 -41
  32. package/kits/basic-2d-frozen/scenes/main.scene +0 -108
  33. package/kits/basic-2d-frozen/vite.config.js +0 -1
  34. package/kits/rpg-2d/.prettierrc +0 -8
  35. package/kits/rpg-2d/behaviors/Camera.tsx +0 -52
  36. package/kits/rpg-2d/behaviors/Collider.tsx +0 -98
  37. package/kits/rpg-2d/behaviors/Dialog.tsx +0 -184
  38. package/kits/rpg-2d/behaviors/Drawing.tsx +0 -161
  39. package/kits/rpg-2d/behaviors/Friend.tsx +0 -45
  40. package/kits/rpg-2d/behaviors/Layout.tsx +0 -29
  41. package/kits/rpg-2d/behaviors/PlayerController.tsx +0 -255
  42. package/kits/rpg-2d/behaviors/Portal.tsx +0 -60
  43. package/kits/rpg-2d/behaviors/QuestLog.tsx +0 -90
  44. package/kits/rpg-2d/behaviors/SaveMenu.tsx +0 -123
  45. package/kits/rpg-2d/behaviors/Tilemap.tsx +0 -90
  46. package/kits/rpg-2d/drawings/bld-home.drawing +0 -8136
  47. package/kits/rpg-2d/drawings/env-crate.drawing +0 -509
  48. package/kits/rpg-2d/drawings/env-fence.drawing +0 -536
  49. package/kits/rpg-2d/drawings/env-flower-bed.drawing +0 -607
  50. package/kits/rpg-2d/drawings/env-fountain.drawing +0 -2622
  51. package/kits/rpg-2d/drawings/env-hedge.drawing +0 -601
  52. package/kits/rpg-2d/drawings/env-house-blue.drawing +0 -1
  53. package/kits/rpg-2d/drawings/env-house-green.drawing +0 -1
  54. package/kits/rpg-2d/drawings/env-tree-oak.drawing +0 -1540
  55. package/kits/rpg-2d/drawings/env-tree-pine.drawing +0 -1315
  56. package/kits/rpg-2d/drawings/floor.drawing +0 -70
  57. package/kits/rpg-2d/drawings/fx-sparkle.drawing +0 -926
  58. package/kits/rpg-2d/drawings/npc-juno-idle-down.drawing +0 -1099
  59. package/kits/rpg-2d/drawings/npc-juno-walk-down.drawing +0 -4177
  60. package/kits/rpg-2d/drawings/npc-opal-idle-down.drawing +0 -1099
  61. package/kits/rpg-2d/drawings/npc-opal-walk-down.drawing +0 -4177
  62. package/kits/rpg-2d/drawings/player-idle-down.drawing +0 -1070
  63. package/kits/rpg-2d/drawings/player-idle-left.drawing +0 -1070
  64. package/kits/rpg-2d/drawings/player-idle-right.drawing +0 -1070
  65. package/kits/rpg-2d/drawings/player-idle-up.drawing +0 -1070
  66. package/kits/rpg-2d/drawings/player-walk-down.drawing +0 -4148
  67. package/kits/rpg-2d/drawings/player-walk-left.drawing +0 -4148
  68. package/kits/rpg-2d/drawings/player-walk-right.drawing +0 -4148
  69. package/kits/rpg-2d/drawings/player-walk-up.drawing +0 -4148
  70. package/kits/rpg-2d/editors/App.tsx +0 -163
  71. package/kits/rpg-2d/editors/CodeEditor.tsx +0 -120
  72. package/kits/rpg-2d/editors/DrawingEditor.tsx +0 -278
  73. package/kits/rpg-2d/editors/FileBrowser.tsx +0 -191
  74. package/kits/rpg-2d/editors/PlayOnly.tsx +0 -26
  75. package/kits/rpg-2d/editors/SceneEditor.tsx +0 -1093
  76. package/kits/rpg-2d/editors/behaviorRegistry.ts +0 -33
  77. package/kits/rpg-2d/editors/editorHistory.ts +0 -75
  78. package/kits/rpg-2d/editors/editorProps.ts +0 -10
  79. package/kits/rpg-2d/engine/ScenePlayer.tsx +0 -130
  80. package/kits/rpg-2d/engine/SceneUI.tsx +0 -74
  81. package/kits/rpg-2d/engine/TouchControls.tsx +0 -157
  82. package/kits/rpg-2d/engine/autoInspector.tsx +0 -111
  83. package/kits/rpg-2d/engine/drawing.ts +0 -81
  84. package/kits/rpg-2d/engine/files.ts +0 -215
  85. package/kits/rpg-2d/engine/scene.ts +0 -484
  86. package/kits/rpg-2d/engine/ui.module.css +0 -928
  87. package/kits/rpg-2d/engine/ui.tsx +0 -483
  88. package/kits/rpg-2d/eslint.config.js +0 -46
  89. package/kits/rpg-2d/index.html +0 -11
  90. package/kits/rpg-2d/main.tsx +0 -14
  91. package/kits/rpg-2d/package-lock.json +0 -3149
  92. package/kits/rpg-2d/package.json +0 -46
  93. package/kits/rpg-2d/scenes/main.scene +0 -203
  94. package/kits/rpg-2d/tsconfig.json +0 -17
  95. package/kits/rpg-2d/vite-env.d.ts +0 -7
  96. 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
- }