castle-web-cli 0.4.77 → 0.4.79

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 (53) hide show
  1. package/dist/agent-prompts.d.ts +4 -1
  2. package/dist/agent-prompts.js +28 -7
  3. package/dist/agent.d.ts +7 -2
  4. package/dist/agent.js +655 -51
  5. package/dist/ide.js +2 -0
  6. package/dist/native/loop.d.ts +2 -0
  7. package/dist/native/loop.js +698 -0
  8. package/dist/native/openrouter.d.ts +55 -0
  9. package/dist/native/openrouter.js +354 -0
  10. package/dist/native/playtest-browser.d.ts +34 -0
  11. package/dist/native/playtest-browser.js +354 -0
  12. package/dist/native/playtest-executor.d.ts +3 -0
  13. package/dist/native/playtest-executor.js +156 -0
  14. package/dist/native/playtest.d.ts +131 -0
  15. package/dist/native/playtest.js +314 -0
  16. package/dist/native/tools.d.ts +38 -0
  17. package/dist/native/tools.js +630 -0
  18. package/dist/native/types.d.ts +40 -0
  19. package/dist/native/types.js +41 -0
  20. package/dist/serve.js +12 -0
  21. package/dist/shell/assets/{index-CvHiGhAV.js → index-CNT3KxJb.js} +37 -37
  22. package/dist/shell/assets/{index-QteLRDnK.css → index-RZrw5gQ2.css} +1 -1
  23. package/dist/shell/index.html +2 -2
  24. package/kits/basic-2d/CLAUDE.md +29 -3
  25. package/kits/basic-2d/behaviors/Layout.jsx +10 -0
  26. package/kits/basic-2d/behaviors/Sprite.jsx +16 -4
  27. package/kits/basic-2d/blueprints/cauldron.scene +22 -0
  28. package/kits/basic-2d/castle.json +5 -7
  29. package/kits/basic-2d/docs/pxart-format.md +83 -4
  30. package/kits/basic-2d/drawings/cauldron.pxart +113 -0
  31. package/kits/basic-2d/editors/BlueprintLibrary.jsx +247 -0
  32. package/kits/basic-2d/editors/PlayOnly.jsx +1 -0
  33. package/kits/basic-2d/editors/PxArtEditor.jsx +68 -9
  34. package/kits/basic-2d/editors/SceneEditor.jsx +424 -418
  35. package/kits/basic-2d/editors/SelectionOverlay.jsx +125 -63
  36. package/kits/basic-2d/editors/SingleEditor.jsx +11 -2
  37. package/kits/basic-2d/editors/editorHistory.js +95 -17
  38. package/kits/basic-2d/editors/inspectorSheet.js +5 -19
  39. package/kits/basic-2d/editors/pixelEditorChrome.jsx +21 -8
  40. package/kits/basic-2d/editors/pixelInspector.jsx +39 -0
  41. package/kits/basic-2d/editors/pxArtEditorModel.js +15 -1
  42. package/kits/basic-2d/engine/ScenePlayer.jsx +2 -2
  43. package/kits/basic-2d/engine/blueprint.js +423 -0
  44. package/kits/basic-2d/engine/files.js +1 -1
  45. package/kits/basic-2d/engine/pxart.js +49 -2
  46. package/kits/basic-2d/engine/pxartSmooth.js +222 -0
  47. package/kits/basic-2d/engine/scene.js +29 -29
  48. package/kits/basic-2d/engine/ui.jsx +160 -21
  49. package/kits/basic-2d/engine/ui.module.css +263 -27
  50. package/kits/basic-2d/pnpm-workspace.yaml +3 -0
  51. package/kits/basic-2d/scenes/main.scene +3 -13
  52. package/package.json +2 -1
  53. package/kits/basic-2d/drawings/pig.pxart +0 -26
@@ -372,8 +372,13 @@
372
372
 
373
373
  .bpSlot,
374
374
  .bpActionSlot {
375
+ position: relative;
375
376
  width: 46px;
376
377
  height: 46px;
378
+ /* Never shrink in the flex hotbar -- keep the square 46x46 and let the
379
+ hotbar scroll (overflow-x: auto) when the panel gets narrow, instead of
380
+ squishing slots (the add button collapsed since its icon is only 14px). */
381
+ flex: 0 0 46px;
377
382
  display: inline-flex;
378
383
  align-items: center;
379
384
  justify-content: center;
@@ -387,11 +392,34 @@
387
392
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
388
393
  }
389
394
 
395
+ .bpSlotBadge {
396
+ position: absolute;
397
+ right: -4px;
398
+ bottom: -4px;
399
+ min-width: 15px;
400
+ height: 15px;
401
+ padding: 0 3px;
402
+ border-radius: 999px;
403
+ background: var(--castle-selected);
404
+ color: var(--castle-selected-ink);
405
+ font-size: 10px;
406
+ font-weight: 700;
407
+ line-height: 15px;
408
+ text-align: center;
409
+ }
410
+
390
411
  .bpSlot:hover,
391
412
  .bpActionSlot:hover {
392
413
  background: var(--castle-inspector-input-bg);
393
414
  }
394
415
 
416
+ .bpSlotSelected,
417
+ .bpSlotSelected:hover {
418
+ border-color: var(--castle-selected);
419
+ box-shadow: 0 0 0 1px var(--castle-selected);
420
+ background: var(--castle-inspector-input-bg);
421
+ }
422
+
395
423
  .bpSlot:disabled,
396
424
  .bpActionSlot:disabled {
397
425
  cursor: default;
@@ -448,6 +476,119 @@
448
476
  flex: 1 1 auto;
449
477
  }
450
478
 
479
+ .confirmBackdrop {
480
+ position: fixed;
481
+ inset: 0;
482
+ z-index: 2000;
483
+ display: flex;
484
+ align-items: center;
485
+ justify-content: center;
486
+ background: rgba(0, 0, 0, 0.55);
487
+ }
488
+
489
+ .confirmDialog {
490
+ width: min(340px, calc(100vw - 32px));
491
+ padding: 18px;
492
+ border: 1px solid var(--castle-border);
493
+ border-radius: 10px;
494
+ background: var(--castle-panel-raised);
495
+ color: var(--castle-text);
496
+ box-shadow: 0 20px 48px rgba(0, 0, 0, 0.5);
497
+ }
498
+
499
+ .confirmTitle {
500
+ font-size: 15px;
501
+ font-weight: 650;
502
+ margin-bottom: 8px;
503
+ }
504
+
505
+ .confirmMessage {
506
+ font-size: 13px;
507
+ color: var(--castle-text-dim);
508
+ line-height: 1.45;
509
+ margin-bottom: 16px;
510
+ }
511
+
512
+ .confirmActions {
513
+ display: flex;
514
+ justify-content: flex-end;
515
+ gap: 8px;
516
+ }
517
+
518
+ .blueprintBadge {
519
+ display: inline-flex;
520
+ align-items: center;
521
+ padding: 2px 7px;
522
+ border-radius: 999px;
523
+ border: 1px solid var(--castle-inspector-border);
524
+ background: var(--castle-inspector-input-bg);
525
+ color: var(--castle-inspector-muted);
526
+ font-size: 11px;
527
+ font-weight: 600;
528
+ letter-spacing: 0.02em;
529
+ text-transform: uppercase;
530
+ }
531
+
532
+ .editorHeaderTitleRow {
533
+ display: inline-flex;
534
+ align-items: center;
535
+ gap: 8px;
536
+ }
537
+
538
+ .instanceHint {
539
+ display: flex;
540
+ align-items: center;
541
+ justify-content: space-between;
542
+ gap: 8px;
543
+ padding: 10px 16px;
544
+ border-bottom: 1px solid var(--castle-inspector-divider);
545
+ }
546
+
547
+ .instanceHintLabel {
548
+ color: var(--castle-inspector-muted);
549
+ font-size: 12px;
550
+ }
551
+
552
+ .instanceForkButton {
553
+ border: 1px solid var(--castle-inspector-border);
554
+ border-radius: 6px;
555
+ background: var(--castle-inspector-input-bg);
556
+ color: inherit;
557
+ font-size: 11px;
558
+ padding: 5px 9px;
559
+ cursor: pointer;
560
+ white-space: nowrap;
561
+ }
562
+
563
+ .instanceForkButton:hover {
564
+ background: var(--castle-inspector-border);
565
+ }
566
+
567
+ /* Editable blueprint title: reads as a heading until hovered/focused, where a
568
+ border + input background reveal that it's editable. */
569
+ .blueprintNameInput {
570
+ flex: 1;
571
+ min-width: 0;
572
+ border: 1px solid transparent;
573
+ border-radius: var(--castle-radius);
574
+ background: transparent;
575
+ color: var(--castle-inspector-text);
576
+ font-size: 14px;
577
+ font-weight: 600;
578
+ padding: 4px 6px;
579
+ margin: -4px -6px;
580
+ outline: 0;
581
+ }
582
+
583
+ .blueprintNameInput:hover {
584
+ border-color: var(--castle-inspector-border);
585
+ }
586
+
587
+ .blueprintNameInput:focus {
588
+ border-color: var(--castle-inspector-border);
589
+ background: var(--castle-inspector-input-bg);
590
+ }
591
+
451
592
  .stageWrap {
452
593
  grid-column: 1;
453
594
  grid-row: 2;
@@ -487,6 +628,9 @@
487
628
  height: 100%;
488
629
  display: block;
489
630
  touch-action: none;
631
+ /* tabIndex=-1 (keyboard-focus capture on pointer-down) would otherwise draw a
632
+ focus ring; focus here is programmatic only, never via keyboard. */
633
+ outline: none;
490
634
  }
491
635
 
492
636
  .stageCanvasEdit {
@@ -578,9 +722,11 @@
578
722
 
579
723
  .selBox {
580
724
  position: absolute;
725
+ box-sizing: border-box;
581
726
  border: 2px dashed var(--castle-text);
582
727
  border-radius: 3px;
583
728
  opacity: 0.85;
729
+ pointer-events: none;
584
730
  }
585
731
 
586
732
  /* Connector stem from the box's right-center edge to the rotate handle. */
@@ -1112,6 +1258,18 @@
1112
1258
  max-height: 100%;
1113
1259
  }
1114
1260
 
1261
+ .canvasTopStack {
1262
+ display: flex;
1263
+ flex-direction: column;
1264
+ gap: 6px;
1265
+ }
1266
+
1267
+ .canvasTopBar {
1268
+ display: flex;
1269
+ align-items: center;
1270
+ gap: 16px;
1271
+ }
1272
+
1115
1273
  .canvasSizeBar {
1116
1274
  display: flex;
1117
1275
  align-items: center;
@@ -1121,6 +1279,54 @@
1121
1279
  color: var(--castle-inspector-muted);
1122
1280
  }
1123
1281
 
1282
+ .cornerRadiusBar {
1283
+ display: flex;
1284
+ align-items: center;
1285
+ gap: 6px;
1286
+ flex: 0 0 auto;
1287
+ font-size: 12px;
1288
+ color: var(--castle-inspector-muted);
1289
+ }
1290
+
1291
+ /* Corner-radius segmented control (0 / ¼ / ½) — same bordered-row-of-
1292
+ buttons pattern as .drawingShapeModeRow, sized for short text labels
1293
+ instead of square glyph buttons. */
1294
+ .cornerRadiusSegments {
1295
+ display: flex;
1296
+ border: 1px solid var(--castle-inspector-border);
1297
+ border-radius: var(--castle-radius);
1298
+ overflow: hidden;
1299
+ }
1300
+
1301
+ .cornerRadiusSegments > * + * {
1302
+ border-left: 1px solid var(--castle-inspector-border);
1303
+ }
1304
+
1305
+ .cornerRadiusSegment {
1306
+ min-width: 28px;
1307
+ padding: 3px 8px;
1308
+ border: 0;
1309
+ background: var(--castle-inspector-button-bg);
1310
+ color: var(--castle-inspector-text);
1311
+ cursor: pointer;
1312
+ font-size: 12px;
1313
+ font-variant-numeric: tabular-nums;
1314
+ line-height: 1.35;
1315
+ }
1316
+
1317
+ .cornerRadiusSegment:hover {
1318
+ background: var(--castle-inspector-input-bg);
1319
+ }
1320
+
1321
+ /* Compound selector (not a bare `.cornerRadiusSegmentOn`) for the same reason
1322
+ documented above `.drawingToolButton.drawingToolSelected`: it must beat
1323
+ `.cornerRadiusSegment:hover` on specificity no matter source order. */
1324
+ .cornerRadiusSegment.cornerRadiusSegmentOn,
1325
+ .cornerRadiusSegment.cornerRadiusSegmentOn:hover {
1326
+ background: var(--castle-selected);
1327
+ color: var(--castle-selected-ink);
1328
+ }
1329
+
1124
1330
  .canvasSizeSep {
1125
1331
  color: var(--castle-inspector-muted);
1126
1332
  user-select: none;
@@ -1306,23 +1512,20 @@
1306
1512
  justify-content: center;
1307
1513
  }
1308
1514
 
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. */
1515
+ /* Stacks the native artboard canvas, the smooth-preview canvas, and the
1516
+ display-resolution overlay so the marching-ants outline renders crisp
1517
+ instead of sub-pixel on the upscaled art. The checkerboard "transparency"
1518
+ background lives on the FRAME (not the main canvas) so it doesn't paint
1519
+ over the smooth-preview canvas underneath in "smooth" render mode. */
1311
1520
  .drawingArtboardFrame {
1312
1521
  position: relative;
1313
1522
  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
-
1324
- .drawingCanvas {
1325
- image-rendering: pixelated;
1523
+ /* Own stacking context, so the negative-z .drawingSmooth canvas paints just
1524
+ above THIS element's checkerboard background instead of sinking below it
1525
+ (without isolation, negative z-index children paint before all in-flow
1526
+ descendant backgrounds of the outer stacking context — checkerboard
1527
+ included — hiding the smooth render entirely). */
1528
+ isolation: isolate;
1326
1529
  background:
1327
1530
  linear-gradient(45deg, #1a1a1a 25%, transparent 25%),
1328
1531
  linear-gradient(-45deg, #1a1a1a 25%, transparent 25%),
@@ -1336,7 +1539,41 @@
1336
1539
  8px -8px,
1337
1540
  -8px 0;
1338
1541
  border: 1px solid var(--castle-inspector-border);
1542
+ }
1543
+
1544
+ .drawingOverlay {
1545
+ position: absolute;
1546
+ inset: 0;
1547
+ width: 100%;
1548
+ height: 100%;
1549
+ pointer-events: none;
1550
+ }
1551
+
1552
+ /* Behind the main canvas (negative z-index paints before static content in
1553
+ the same containing block) — holds the corner-rounded render for "smooth"
1554
+ sprites while the main canvas above it stays transparent except for tool
1555
+ overlays, so editing interactions are unaffected. Empty/0-sized in "pixel"
1556
+ mode. */
1557
+ .drawingSmooth {
1558
+ position: absolute;
1559
+ inset: 0;
1560
+ width: 100%;
1561
+ height: 100%;
1562
+ pointer-events: none;
1563
+ z-index: -1;
1564
+ }
1565
+
1566
+ .drawingCanvas {
1567
+ image-rendering: pixelated;
1568
+ position: absolute;
1569
+ inset: 0;
1570
+ width: 100%;
1571
+ height: 100%;
1339
1572
  flex: 0 0 auto;
1573
+ /* tabIndex=-1 (for keyboard-focus capture on pointer-down) would otherwise
1574
+ draw a focus ring around the artboard; it's focused programmatically, never
1575
+ via keyboard, so suppressing the outline is safe. */
1576
+ outline: none;
1340
1577
  }
1341
1578
 
1342
1579
  .palette {
@@ -1640,8 +1877,9 @@
1640
1877
 
1641
1878
  @media (max-width: 600px) {
1642
1879
  :root {
1880
+ /* Fallback for the file-browser sheet and the inspector's initial slide-in;
1881
+ the inspector's live height is driven by the hook's --sheet-h (see below). */
1643
1882
  --sheet-high-height: 62vh;
1644
- --sheet-low-height: 18vh;
1645
1883
  }
1646
1884
 
1647
1885
  /* `display: contents` makes wrapper spans transparent in layout so their
@@ -1789,7 +2027,7 @@
1789
2027
  overflow-y: auto;
1790
2028
  }
1791
2029
 
1792
- /* Inspector sheet: hidden off-screen by default; slides up to high (full) or low (partial). */
2030
+ /* Inspector sheet: hidden off-screen by default; slides up when open. */
1793
2031
  .inspector {
1794
2032
  z-index: 45;
1795
2033
  border-left: 0;
@@ -1797,20 +2035,18 @@
1797
2035
  padding: 0;
1798
2036
  }
1799
2037
 
1800
- .inspector[data-sheet-snap='high'] {
1801
- transform: translateY(0);
1802
- height: var(--sheet-high-height);
1803
- }
1804
-
1805
- .inspector[data-sheet-snap='low'] {
2038
+ /* Open inspector sheet: continuous height driven by the hook's live --sheet-h
2039
+ (falls back to the default expanded height). Drag the grab handle to resize
2040
+ freely; the hook picks the settle point on release. */
2041
+ .inspector[data-sheet-open='true'] {
1806
2042
  transform: translateY(0);
1807
- height: var(--sheet-low-height);
2043
+ height: var(--sheet-h, var(--sheet-high-height));
1808
2044
  }
1809
2045
 
1810
- /* Auto-height variant -- inspector hugs its content at the high snap (drawing/code). */
1811
- .inspector.inspectorAuto[data-sheet-snap='high'] {
1812
- height: auto;
1813
- max-height: var(--sheet-high-height);
2046
+ /* While dragging, drop the transition so the sheet tracks the finger 1:1; the
2047
+ settle animation returns the moment this class is removed on release. */
2048
+ .inspector.sheetDragging {
2049
+ transition: none;
1814
2050
  }
1815
2051
 
1816
2052
  /* Shared sheet chrome -- grab bar pill + label row. Always visible when sheet is visible. */
@@ -0,0 +1,3 @@
1
+ allowBuilds:
2
+ '@fortawesome/fontawesome-common-types': set this to true or false
3
+ '@fortawesome/free-solid-svg-icons': set this to true or false
@@ -1,23 +1,13 @@
1
1
  {
2
- "background": "#00396D",
2
+ "background": "#1a1932",
3
3
  "actors": [
4
4
  {
5
5
  "id": "pig",
6
+ "blueprint": "blueprints/cauldron.scene",
6
7
  "components": {
7
8
  "Layout": {
8
9
  "x": 210,
9
- "y": 310,
10
- "width": 80,
11
- "height": 80,
12
- "z": 1
13
- },
14
- "Sprite": {
15
- "file": "drawings/pig.pxart"
16
- },
17
- "Collider": {
18
- "kind": "solid",
19
- "width": 70,
20
- "height": 70
10
+ "y": 310
21
11
  }
22
12
  }
23
13
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "castle-web-cli",
3
- "version": "0.4.77",
3
+ "version": "0.4.79",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "castle-web": "./dist/index.js"
@@ -40,6 +40,7 @@
40
40
  "nanoid": "^5.1.7",
41
41
  "open": "^10.0.0",
42
42
  "picomatch": "^4.0.4",
43
+ "playwright-core": "^1.61.1",
43
44
  "react": "^18.3.1",
44
45
  "react-dom": "^18.3.1",
45
46
  "vite": "^8.0.3",
@@ -1,26 +0,0 @@
1
- {
2
- "format": "compact",
3
- "palette": {
4
- "6": "#f5555d",
5
- "q": "#391f21",
6
- "v": "#f6ca9f"
7
- },
8
- "grid": [
9
- "................",
10
- "................",
11
- "........q..q....",
12
- "....qqqqvqqvq...",
13
- "...qvvvvvvvvq...",
14
- "..qvvvvvvvvvvq..",
15
- ".qvvvvvvvqvvqvq.",
16
- ".qvvvvvvvqvvqvq.",
17
- "q6vvvvvvvvv666q.",
18
- "q6vvvvvvvv6q6q6q",
19
- ".qvvvvvvvv66666q",
20
- ".qvvvvvvvvv666q.",
21
- "..qvvvvvvvvvqq..",
22
- "..q66qqqq6q6q...",
23
- "..q6q...q6q.....",
24
- "................"
25
- ]
26
- }