castle-web-cli 0.4.84 → 0.4.86

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 (90) hide show
  1. package/dist/ide.js +35 -13
  2. package/dist/shell/assets/{index-BOgm5T3W.js → index-BJLaUTJE.js} +21 -21
  3. package/dist/shell/index.html +1 -1
  4. package/kits/basic-2d/CLAUDE.md +3 -3
  5. package/kits/basic-2d/behaviors/Collider.jsx +172 -26
  6. package/kits/basic-2d/behaviors/Layout.jsx +24 -0
  7. package/kits/basic-2d/editors/PlayOnly.jsx +11 -9
  8. package/kits/basic-2d/editors/SceneEditor.jsx +49 -16
  9. package/kits/basic-2d/editors/SelectionOverlay.jsx +21 -11
  10. package/kits/basic-2d/editors/behaviorRegistry.js +9 -3
  11. package/kits/basic-2d/engine/behaviorExtensions.js +28 -0
  12. package/kits/basic-2d/engine/collider.js +60 -6
  13. package/kits/basic-2d/engine/scene.js +28 -2
  14. package/kits/basic-2d/engine/systemRegistry.js +12 -0
  15. package/kits/basic-2d/engine/ui.jsx +2 -0
  16. package/kits/basic-2d/main.jsx +3 -2
  17. package/kits/physics-2d/.prettierrc +8 -0
  18. package/kits/physics-2d/CLAUDE.md +329 -0
  19. package/kits/physics-2d/behaviors/Camera.jsx +43 -0
  20. package/kits/physics-2d/behaviors/Collider.jsx +213 -0
  21. package/kits/physics-2d/behaviors/Goal.jsx +29 -0
  22. package/kits/physics-2d/behaviors/Layout.jsx +53 -0
  23. package/kits/physics-2d/behaviors/Sprite.jsx +352 -0
  24. package/kits/physics-2d/behaviors/tint.js +47 -0
  25. package/kits/physics-2d/blueprints/ball.scene +14 -0
  26. package/kits/physics-2d/blueprints/block.scene +12 -0
  27. package/kits/physics-2d/blueprints/cauldron.scene +18 -0
  28. package/kits/physics-2d/blueprints/crate.scene +14 -0
  29. package/kits/physics-2d/blueprints/goal.scene +12 -0
  30. package/kits/physics-2d/castle.json +13 -0
  31. package/kits/physics-2d/docs/pxart-format.md +377 -0
  32. package/kits/physics-2d/drawings/block.pxart +25 -0
  33. package/kits/physics-2d/drawings/cauldron.pxart +113 -0
  34. package/kits/physics-2d/editors/BlueprintLibrary.jsx +247 -0
  35. package/kits/physics-2d/editors/ErrorBoundary.jsx +59 -0
  36. package/kits/physics-2d/editors/PlayOnly.jsx +31 -0
  37. package/kits/physics-2d/editors/PxArtEditor.jsx +954 -0
  38. package/kits/physics-2d/editors/SceneEditor.jsx +1696 -0
  39. package/kits/physics-2d/editors/SelectionOverlay.jsx +909 -0
  40. package/kits/physics-2d/editors/SingleEditor.jsx +122 -0
  41. package/kits/physics-2d/editors/behaviorRegistry.js +30 -0
  42. package/kits/physics-2d/editors/editorHistory.js +157 -0
  43. package/kits/physics-2d/editors/inspectorSheet.js +13 -0
  44. package/kits/physics-2d/editors/pixelCanvas.js +11 -0
  45. package/kits/physics-2d/editors/pixelEditorChrome.jsx +74 -0
  46. package/kits/physics-2d/editors/pixelGeometry.js +140 -0
  47. package/kits/physics-2d/editors/pixelInspector.jsx +633 -0
  48. package/kits/physics-2d/editors/pxArtEditorModel.js +732 -0
  49. package/kits/physics-2d/editors/pxArtPlayback.js +92 -0
  50. package/kits/physics-2d/editors/pxArtTimeline.jsx +752 -0
  51. package/kits/physics-2d/editors/pxArtTimeline.module.css +506 -0
  52. package/kits/physics-2d/editors/pxArtTools.js +232 -0
  53. package/kits/physics-2d/editors/useArtboardFit.js +102 -0
  54. package/kits/physics-2d/engine/ScenePlayer.jsx +196 -0
  55. package/kits/physics-2d/engine/SceneUI.jsx +59 -0
  56. package/kits/physics-2d/engine/assets.js +15 -0
  57. package/kits/physics-2d/engine/autoInspector.jsx +70 -0
  58. package/kits/physics-2d/engine/behaviorExtensions.js +28 -0
  59. package/kits/physics-2d/engine/blueprint.js +521 -0
  60. package/kits/physics-2d/engine/collider.js +200 -0
  61. package/kits/physics-2d/engine/files.js +117 -0
  62. package/kits/physics-2d/engine/liveReload.js +88 -0
  63. package/kits/physics-2d/engine/pxart.js +1032 -0
  64. package/kits/physics-2d/engine/pxartSmooth.js +222 -0
  65. package/kits/physics-2d/engine/scene.js +685 -0
  66. package/kits/physics-2d/engine/spriteGeometry.js +32 -0
  67. package/kits/physics-2d/engine/systemRegistry.js +12 -0
  68. package/kits/physics-2d/engine/ui.jsx +688 -0
  69. package/kits/physics-2d/engine/ui.module.css +2287 -0
  70. package/kits/physics-2d/eslint.config.js +71 -0
  71. package/kits/physics-2d/index.html +24 -0
  72. package/kits/physics-2d/main.jsx +24 -0
  73. package/kits/physics-2d/package-lock.json +2706 -0
  74. package/kits/physics-2d/package.json +42 -0
  75. package/kits/physics-2d/physics/PhysicsSystem.js +290 -0
  76. package/kits/physics-2d/physics/behaviors/AnalogStick.jsx +101 -0
  77. package/kits/physics-2d/physics/behaviors/Draggable.jsx +79 -0
  78. package/kits/physics-2d/physics/behaviors/RigidBody.jsx +55 -0
  79. package/kits/physics-2d/physics/behaviors/Slingshot.jsx +118 -0
  80. package/kits/physics-2d/physics/controls.js +79 -0
  81. package/kits/physics-2d/physics/extensions/collider.js +15 -0
  82. package/kits/physics-2d/physics/index.js +26 -0
  83. package/kits/physics-2d/physics/matterBridge.js +126 -0
  84. package/kits/physics-2d/pnpm-lock.yaml +1761 -0
  85. package/kits/physics-2d/scenes/main.scene +12 -0
  86. package/kits/physics-2d/scenes/sandbox.scene +13 -0
  87. package/kits/physics-2d/scripts/draw.mjs +121 -0
  88. package/kits/physics-2d/systems/physics.js +8 -0
  89. package/kits/physics-2d/vite.config.js +1 -0
  90. package/package.json +1 -1
@@ -0,0 +1,506 @@
1
+ /* Layers x frames timeline panel for the PxArt editor. Sits below the artboard
2
+ in the editor's left column: a toolbar row, a horizontally-scrolling
3
+ layers(rows) x frames(columns) grid, then the tags panel. Colors reuse the
4
+ shared inspector CSS variables from engine/ui.module.css. */
5
+
6
+ /* The editor's left column: artboard region stacked above the timeline. Takes
7
+ grid column 1 of the shared .drawingEditor grid (the inspector is column 2). */
8
+ .editorLeft {
9
+ grid-column: 1;
10
+ grid-row: 1;
11
+ display: flex;
12
+ flex-direction: column;
13
+ min-width: 0;
14
+ min-height: 0;
15
+ }
16
+
17
+ .artboardRegion {
18
+ flex: 1 1 0;
19
+ min-height: 0;
20
+ display: flex;
21
+ overflow: hidden;
22
+ }
23
+
24
+ @container editor (max-width: 620px) {
25
+ .barLabel {
26
+ display: none;
27
+ }
28
+ }
29
+
30
+ /* Height is driven by an inline style from the resize handle (see
31
+ pxArtTimeline.jsx); flex-shrink stays 0 so the artboard region above keeps
32
+ the remainder. */
33
+ .timeline {
34
+ position: relative;
35
+ flex: 0 0 auto;
36
+ display: flex;
37
+ flex-direction: column;
38
+ min-height: 0;
39
+ border-top: 1px solid var(--castle-inspector-divider);
40
+ background: var(--castle-workspace-bg);
41
+ color: var(--castle-inspector-text);
42
+ font-size: 13px;
43
+ overflow: hidden;
44
+ }
45
+
46
+ /* Drag target sitting over the top divider. Absolute so it consumes no layout.
47
+ Neutral hover/active treatment (no accent/purple highlight) to stay
48
+ consistent with the editor's existing chrome. */
49
+ .resizeHandle {
50
+ position: absolute;
51
+ top: -3px;
52
+ left: 0;
53
+ right: 0;
54
+ height: 7px;
55
+ cursor: row-resize;
56
+ background: transparent;
57
+ z-index: 5;
58
+ touch-action: none;
59
+ }
60
+
61
+ .resizeHandle:hover {
62
+ background: var(--castle-inspector-border);
63
+ }
64
+
65
+ .resizeHandleActive,
66
+ .resizeHandleActive:hover {
67
+ background: var(--castle-inspector-muted);
68
+ }
69
+
70
+ .bar {
71
+ display: flex;
72
+ align-items: center;
73
+ flex-wrap: wrap;
74
+ gap: 14px;
75
+ padding: 8px;
76
+ border-bottom: 1px solid var(--castle-inspector-divider);
77
+ }
78
+
79
+ .barGroup {
80
+ display: flex;
81
+ align-items: center;
82
+ gap: 6px;
83
+ }
84
+
85
+ .barLabel {
86
+ color: var(--castle-inspector-muted);
87
+ font-size: 12px;
88
+ text-transform: uppercase;
89
+ letter-spacing: 0.04em;
90
+ }
91
+
92
+ .barSpacer {
93
+ flex: 1 1 auto;
94
+ }
95
+
96
+ .barUnit {
97
+ color: var(--castle-inspector-muted);
98
+ font-size: 11px;
99
+ }
100
+
101
+ .globalDuration {
102
+ width: 56px;
103
+ border: 1px solid var(--castle-inspector-border);
104
+ border-radius: var(--castle-radius);
105
+ background: var(--castle-inspector-input-bg);
106
+ color: var(--castle-inspector-text);
107
+ padding: 4px 6px;
108
+ text-align: center;
109
+ }
110
+
111
+ /* Icon-only label (stopwatch) sitting next to the global duration input, in
112
+ place of the old "Duration … ms · all frames" text. */
113
+ .durationIcon {
114
+ display: inline-flex;
115
+ align-items: center;
116
+ color: var(--castle-inspector-muted);
117
+ }
118
+
119
+ .durationGlyph {
120
+ width: 14px;
121
+ height: 14px;
122
+ fill: currentColor;
123
+ }
124
+
125
+ .miniInput {
126
+ width: 64px;
127
+ border: 1px solid var(--castle-inspector-border);
128
+ border-radius: var(--castle-radius);
129
+ background: var(--castle-inspector-input-bg);
130
+ color: var(--castle-inspector-text);
131
+ padding: 4px 6px;
132
+ }
133
+
134
+ .scroll {
135
+ flex: 1 1 0;
136
+ min-height: 0;
137
+ overflow: auto;
138
+ }
139
+
140
+ .grid {
141
+ display: inline-flex;
142
+ flex-direction: column;
143
+ min-width: 100%;
144
+ }
145
+
146
+ .row {
147
+ display: flex;
148
+ align-items: stretch;
149
+ }
150
+
151
+ /* Grid separators: every grid element (corner, frame headers, layer headers,
152
+ and art cells) draws a SINGLE 1px right+bottom divider. Interior edges are
153
+ each owned by exactly one element (no two borders meet), so there are no
154
+ doubled/thicker seams. The grid's outer top is the toolbar's existing bottom
155
+ divider; outer right/bottom come from the last cells. */
156
+ .corner {
157
+ flex: 0 0 168px;
158
+ border-right: 1px solid var(--castle-inspector-divider);
159
+ border-bottom: 1px solid var(--castle-inspector-divider);
160
+ background: var(--castle-workspace-bg);
161
+ position: sticky;
162
+ left: 0;
163
+ z-index: 2;
164
+ }
165
+
166
+ .frameHead {
167
+ flex: 0 0 52px;
168
+ display: flex;
169
+ flex-direction: column;
170
+ align-items: center;
171
+ gap: 2px;
172
+ padding: 4px 3px;
173
+ border-right: 1px solid var(--castle-inspector-divider);
174
+ border-bottom: 1px solid var(--castle-inspector-divider);
175
+ background: transparent;
176
+ color: var(--castle-inspector-muted);
177
+ cursor: pointer;
178
+ }
179
+
180
+ .frameHeadActive {
181
+ background: var(--castle-black);
182
+ color: var(--castle-text);
183
+ }
184
+
185
+ .frameNum {
186
+ font-variant-numeric: tabular-nums;
187
+ font-size: 12px;
188
+ }
189
+
190
+ .durationInput {
191
+ width: 44px;
192
+ border: 1px solid var(--castle-inspector-border);
193
+ border-radius: 3px;
194
+ background: var(--castle-inspector-input-bg);
195
+ color: var(--castle-inspector-text);
196
+ padding: 1px 3px;
197
+ font-size: 11px;
198
+ text-align: center;
199
+ }
200
+
201
+ /* An OVERRIDDEN frame duration: accented + bold so it reads distinctly from the
202
+ greyed placeholder shown by frames that inherit the global. */
203
+ .durationOverride {
204
+ color: var(--castle-text);
205
+ font-weight: 600;
206
+ border-color: var(--castle-blue);
207
+ }
208
+
209
+ .layerHead {
210
+ flex: 0 0 168px;
211
+ display: flex;
212
+ flex-direction: column;
213
+ justify-content: center;
214
+ gap: 4px;
215
+ padding: 4px 8px;
216
+ border-right: 1px solid var(--castle-inspector-divider);
217
+ border-bottom: 1px solid var(--castle-inspector-divider);
218
+ background: var(--castle-workspace-bg);
219
+ position: sticky;
220
+ left: 0;
221
+ z-index: 1;
222
+ cursor: pointer;
223
+ }
224
+
225
+ .layerHeadActive {
226
+ background: var(--castle-black);
227
+ }
228
+
229
+ .layerTopRow {
230
+ display: flex;
231
+ align-items: center;
232
+ gap: 6px;
233
+ }
234
+
235
+ .visBtn {
236
+ flex: 0 0 auto;
237
+ width: 22px;
238
+ height: 22px;
239
+ display: inline-flex;
240
+ align-items: center;
241
+ justify-content: center;
242
+ border: 1px solid var(--castle-inspector-border);
243
+ border-radius: var(--castle-radius);
244
+ background: var(--castle-inspector-button-bg);
245
+ color: var(--castle-inspector-text);
246
+ cursor: pointer;
247
+ padding: 0;
248
+ }
249
+
250
+ .visBtn:hover {
251
+ background: var(--castle-inspector-input-bg);
252
+ }
253
+
254
+ .visBtn svg {
255
+ width: 12px;
256
+ height: 12px;
257
+ }
258
+
259
+ /* Inline FA eye / eye-slash glyph for the visibility toggle (see FaGlyph). */
260
+ .visGlyph {
261
+ width: 12px;
262
+ height: 12px;
263
+ fill: currentColor;
264
+ }
265
+
266
+ /* Hidden layer: the visibility toggle borrows the standard disabled LOOK
267
+ (0.35 dimming, matching the undo button) without being disabled -- this
268
+ button stays interactive and toggles default <-> disabled-look. */
269
+ .visOff {
270
+ opacity: 0.35;
271
+ }
272
+
273
+ /* Static layer-name label (rename was removed from the UI). */
274
+ .name {
275
+ flex: 1 1 auto;
276
+ min-width: 0;
277
+ overflow: hidden;
278
+ text-overflow: ellipsis;
279
+ white-space: nowrap;
280
+ background: none;
281
+ border: 0;
282
+ color: inherit;
283
+ text-align: left;
284
+ padding: 0;
285
+ }
286
+
287
+ /* Slim opacity slider: a thin custom track + small thumb so the layer header
288
+ cell stays no taller than the art (thumbnail) cells in its row. */
289
+ .opacity {
290
+ width: 100%;
291
+ height: 12px;
292
+ margin: 0;
293
+ cursor: pointer;
294
+ appearance: none;
295
+ -webkit-appearance: none;
296
+ background: transparent;
297
+ accent-color: var(--castle-selected);
298
+ }
299
+
300
+ .opacity::-webkit-slider-runnable-track {
301
+ height: 3px;
302
+ border-radius: 2px;
303
+ background: var(--castle-inspector-border);
304
+ }
305
+
306
+ .opacity::-webkit-slider-thumb {
307
+ -webkit-appearance: none;
308
+ appearance: none;
309
+ width: 10px;
310
+ height: 10px;
311
+ margin-top: -3.5px;
312
+ border-radius: 50%;
313
+ background: var(--castle-selected);
314
+ }
315
+
316
+ .opacity::-moz-range-track {
317
+ height: 3px;
318
+ border-radius: 2px;
319
+ background: var(--castle-inspector-border);
320
+ }
321
+
322
+ .opacity::-moz-range-thumb {
323
+ width: 10px;
324
+ height: 10px;
325
+ border: 0;
326
+ border-radius: 50%;
327
+ background: var(--castle-selected);
328
+ }
329
+
330
+ /* The cell is a real <button>, so wipe the UA button chrome first. Crucially
331
+ `border: 0` clears the default TOP/LEFT borders the UA otherwise keeps (we only
332
+ override right/bottom below) — those surviving defaults were the "heavier /
333
+ doubled" top-left edge. The reset comes BEFORE the divider longhands so our
334
+ right+bottom separators still apply; the selected-cell inset stroke lives on
335
+ .cellActive (box-shadow) and is unaffected by this border reset. */
336
+ .cell {
337
+ appearance: none;
338
+ -webkit-appearance: none;
339
+ margin: 0;
340
+ border: 0;
341
+ background: none;
342
+ font: inherit;
343
+ color: inherit;
344
+ text-align: center;
345
+ box-sizing: border-box;
346
+ flex: 0 0 52px;
347
+ height: 52px;
348
+ display: flex;
349
+ align-items: center;
350
+ justify-content: center;
351
+ padding: 4px;
352
+ border-right: 1px solid var(--castle-inspector-divider);
353
+ border-bottom: 1px solid var(--castle-inspector-divider);
354
+ cursor: pointer;
355
+ position: relative;
356
+ }
357
+
358
+ .cellActive {
359
+ background: rgb(141 183 255 / 0.16);
360
+ box-shadow: inset 0 0 0 2px var(--castle-blue);
361
+ }
362
+
363
+ .thumb {
364
+ width: 100%;
365
+ height: 100%;
366
+ }
367
+
368
+ .thumbCanvas {
369
+ width: 100%;
370
+ height: 100%;
371
+ image-rendering: pixelated;
372
+ display: block;
373
+ }
374
+
375
+ /* Empty/absent cell: plain and empty. The cell's own grid separators (see the
376
+ .corner/.cell border rules) still bound it; there's no dashed interior. */
377
+ .empty {
378
+ width: 100%;
379
+ height: 100%;
380
+ background: transparent;
381
+ }
382
+
383
+ .linkBadge {
384
+ position: absolute;
385
+ left: 5px;
386
+ top: 5px;
387
+ width: 14px;
388
+ height: 14px;
389
+ display: inline-flex;
390
+ align-items: center;
391
+ justify-content: center;
392
+ /* Match the thumb/.linkRing corner rounding (2px). A larger radius left a
393
+ sliver of the parent's rounded corner peeking behind the badge. */
394
+ border-radius: 2px;
395
+ background: var(--castle-blue);
396
+ color: var(--castle-selected-ink);
397
+ }
398
+
399
+ .linkBadge svg {
400
+ width: 9px;
401
+ height: 9px;
402
+ }
403
+
404
+ .linkRing {
405
+ box-shadow: inset 0 0 0 1px var(--castle-blue);
406
+ border-radius: 2px;
407
+ }
408
+
409
+ /* Fade only the linked cell's thumbnail IMAGE (the canvas) to signal a shared
410
+ image. Scoped to the canvas inside a linked thumb, so the blue ring
411
+ (.linkRing box-shadow) and the link badge (.linkBadge) stay full opacity. */
412
+ .linkRing .thumbCanvas {
413
+ opacity: 0.5;
414
+ }
415
+
416
+ .tags {
417
+ flex: 0 0 auto;
418
+ max-height: 38%;
419
+ overflow: auto;
420
+ border-top: 1px solid var(--castle-inspector-divider);
421
+ padding: 8px 12px;
422
+ }
423
+
424
+ .tagsHead {
425
+ display: flex;
426
+ align-items: center;
427
+ gap: 10px;
428
+ margin-bottom: 8px;
429
+ }
430
+
431
+ .tagRow {
432
+ display: flex;
433
+ align-items: center;
434
+ gap: 6px;
435
+ margin-bottom: 6px;
436
+ }
437
+
438
+ .tagName {
439
+ flex: 1 1 90px;
440
+ min-width: 0;
441
+ border: 1px solid var(--castle-inspector-border);
442
+ border-radius: 3px;
443
+ background: var(--castle-inspector-input-bg);
444
+ color: var(--castle-inspector-text);
445
+ padding: 3px 6px;
446
+ }
447
+
448
+ .tagNum {
449
+ width: 46px;
450
+ border: 1px solid var(--castle-inspector-border);
451
+ border-radius: 3px;
452
+ background: var(--castle-inspector-input-bg);
453
+ color: var(--castle-inspector-text);
454
+ padding: 3px 4px;
455
+ text-align: center;
456
+ }
457
+
458
+ .tagSelect {
459
+ border: 1px solid var(--castle-inspector-border);
460
+ border-radius: 3px;
461
+ background: var(--castle-inspector-input-bg);
462
+ color: var(--castle-inspector-text);
463
+ padding: 3px 4px;
464
+ }
465
+
466
+ .tagDefault {
467
+ flex: 0 0 auto;
468
+ width: 24px;
469
+ height: 24px;
470
+ display: inline-flex;
471
+ align-items: center;
472
+ justify-content: center;
473
+ border: 1px solid var(--castle-inspector-border);
474
+ border-radius: var(--castle-radius);
475
+ background: var(--castle-inspector-button-bg);
476
+ color: var(--castle-inspector-muted);
477
+ cursor: pointer;
478
+ padding: 0;
479
+ }
480
+
481
+ .tagDefault:hover {
482
+ background: var(--castle-inspector-input-bg);
483
+ }
484
+
485
+ .tagDefaultOn,
486
+ .tagDefaultOn:hover {
487
+ background: var(--castle-selected);
488
+ border-color: var(--castle-selected);
489
+ color: var(--castle-selected-ink);
490
+ }
491
+
492
+ .tagDefault svg {
493
+ width: 12px;
494
+ height: 12px;
495
+ }
496
+
497
+ .muted {
498
+ color: var(--castle-inspector-muted);
499
+ font-size: 12px;
500
+ }
501
+
502
+ /* Disabled right-click menu item (reuses the shared selArrangeItem chrome). */
503
+ .menuItemDisabled {
504
+ opacity: 0.4;
505
+ cursor: default;
506
+ }