castle-web-cli 0.4.169 → 0.4.171
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 +1 -0
- package/dist/agent-prompts.js +3 -0
- package/dist/agent.js +70 -24
- package/dist/atomicFile.d.ts +29 -0
- package/dist/atomicFile.js +120 -0
- package/dist/castle-host/host.js +108 -0
- package/dist/get-deck.js +2 -11
- package/dist/headlessCover.d.ts +4 -0
- package/dist/headlessCover.js +7 -5
- package/dist/ide.d.ts +10 -0
- package/dist/ide.js +19 -11
- package/dist/index.js +10 -6
- package/dist/init.d.ts +1 -1
- package/dist/init.js +11 -1
- package/dist/remix.js +2 -14
- package/dist/save-deck.d.ts +3 -0
- package/dist/save-deck.js +40 -73
- package/dist/saveCover.d.ts +18 -0
- package/dist/saveCover.js +61 -0
- package/dist/serve.js +18 -5
- package/dist/serveSecurity.d.ts +11 -1
- package/dist/serveSecurity.js +38 -4
- package/dist/shell/assets/index-6odVZQSZ.css +1 -0
- package/dist/shell/assets/index-Ws0WrCbi.js +445 -0
- package/dist/shell/index.html +3 -3
- package/dist/versionStore.js +13 -4
- package/kits/base/CLAUDE.md +9 -0
- package/kits/base/castle.json +16 -11
- package/kits/base/sdk/README.md +83 -2
- package/kits/base/sdk/commands.d.ts +37 -1
- package/kits/base/sdk/commands.js +9 -0
- package/kits/base/sdk/lifecycle.d.ts +20 -0
- package/kits/base/sdk/lifecycle.js +7 -1
- package/kits/base/sdk/resumeState.d.ts +2 -0
- package/kits/base/sdk/resumeState.js +84 -0
- package/kits/base/sdk/runtime.js +65 -0
- package/kits/base/sdk/transport.d.ts +3 -0
- package/kits/base/sdk/transport.js +39 -5
- package/kits/base/sdk/unloadHandshake.d.ts +6 -0
- package/kits/base/sdk/unloadHandshake.js +47 -0
- package/kits/base/sdk/user.d.ts +4 -0
- package/kits/base/sdk/user.js +36 -1
- package/kits/multiplayer-2d/CLAUDE.md +20 -9
- package/kits/multiplayer-2d/castle.json +4 -4
- package/kits/multiplayer-2d/code/server/players.js +27 -6
- package/kits/multiplayer-2d/code/server/world.js +24 -1
- package/kits/multiplayer-2d/code/systems/multiplayer.js +45 -4
- package/kits/multiplayer-2d/package-lock.json +2 -4
- package/kits/multiplayer-2d/package.json +1 -0
- package/kits/multiplayer-3d/CLAUDE.md +28 -9
- package/kits/multiplayer-3d/castle.json +5 -5
- package/kits/multiplayer-3d/code/server/players.js +54 -5
- package/kits/multiplayer-3d/code/server/world.js +45 -1
- package/kits/multiplayer-3d/code/systems/multiplayer.js +108 -6
- package/kits/multiplayer-3d/package-lock.json +2 -4
- package/kits/multiplayer-3d/package.json +1 -0
- package/kits/physics-2d/CLAUDE.md +75 -43
- package/kits/physics-2d/behaviors/AnalogStick.jsx +75 -45
- package/kits/physics-2d/behaviors/Slingshot.jsx +1 -2
- package/kits/physics-2d/castle.json +6 -6
- package/kits/physics-2d/editors/PxArtEditor.jsx +85 -182
- package/kits/physics-2d/editors/SceneEditor.jsx +25 -4
- package/kits/physics-2d/editors/StyleEditor.jsx +6 -2
- package/kits/physics-2d/editors/overlayCanvas.js +77 -0
- package/kits/physics-2d/editors/pathOverlay.js +5 -13
- package/kits/physics-2d/editors/pixelEditorChrome.jsx +5 -1
- package/kits/physics-2d/editors/pixelInspector.jsx +4 -4
- package/kits/physics-2d/editors/pxArtTimeline.jsx +8 -36
- package/kits/physics-2d/editors/pxArtTimeline.module.css +4 -28
- package/kits/physics-2d/editors/styleEditor.module.css +23 -4
- package/kits/physics-2d/editors/useArtboardZoomPan.js +322 -0
- package/kits/physics-2d/engine/SceneUI.jsx +6 -12
- package/kits/physics-2d/engine/icons.js +56 -0
- package/kits/physics-2d/engine/panelSorting.jsx +7 -14
- package/kits/physics-2d/engine/physics/PhysicsSystem.js +66 -11
- package/kits/physics-2d/engine/physics/controls.js +76 -12
- package/kits/physics-2d/engine/scene.js +47 -9
- package/kits/physics-2d/engine/ui.jsx +13 -125
- package/kits/physics-2d/engine/ui.module.css +53 -28
- package/kits/physics-2d/package-lock.json +0 -29
- package/kits/physics-2d/package.json +3 -1
- package/kits/physics-2d/pnpm-lock.yaml +1 -17
- package/kits/physics-3d/behaviors/Pickup.jsx +5 -3
- package/kits/physics-3d/castle.json +5 -5
- package/kits/physics-3d/package-lock.json +0 -29
- package/kits/physics-3d/package.json +0 -1
- package/kits/physics-3d/pnpm-lock.yaml +0 -17
- package/kits/real-time/CLAUDE.md +23 -4
- package/kits/real-time/castle.json +1 -1
- package/kits/real-time/code/client/connection.js +9 -4
- package/kits/real-time/code/client/joinOverlay.js +46 -0
- package/kits/real-time/code/client/messages.js +4 -0
- package/kits/real-time/code/server/gameHooks.js +4 -0
- package/kits/real-time/code/server/persist.js +105 -0
- package/kits/real-time/code/server/session.js +289 -19
- package/kits/real-time/package-lock.json +1139 -0
- package/kits/turn-based/CLAUDE.md +76 -20
- package/kits/turn-based/castle.json +3 -3
- package/kits/turn-based/code/server/index.js +16 -5
- package/kits/turn-based/package-lock.json +0 -27
- package/kits/turn-based/package.json +2 -2
- package/kits/turn-based/room.js +162 -13
- package/kits/turn-based/testing.js +276 -92
- package/package.json +5 -5
- package/dist/shell/assets/index-CVHj503j.css +0 -1
- package/dist/shell/assets/index-x_QkP3Xq.js +0 -444
|
@@ -823,10 +823,10 @@
|
|
|
823
823
|
margin-top: 14px;
|
|
824
824
|
}
|
|
825
825
|
|
|
826
|
-
/*
|
|
827
|
-
pencil sits in the corner rather than replacing the art on
|
|
828
|
-
there is no hover, and the affordance has to be visible
|
|
829
|
-
touched. */
|
|
826
|
+
/* Thumbnail that opens the sprite editor (blueprint header + actor instance
|
|
827
|
+
header). The pencil sits in the corner rather than replacing the art on
|
|
828
|
+
hover: on touch there is no hover, and the affordance has to be visible
|
|
829
|
+
before it is touched. */
|
|
830
830
|
.editSpriteButton {
|
|
831
831
|
position: relative;
|
|
832
832
|
display: inline-flex;
|
|
@@ -1161,9 +1161,9 @@
|
|
|
1161
1161
|
height: 300%;
|
|
1162
1162
|
}
|
|
1163
1163
|
|
|
1164
|
-
/*
|
|
1165
|
-
Behavior `ui` output lands in `.sceneUiLayer`,
|
|
1166
|
-
and scaled onto the canvas box. */
|
|
1164
|
+
/* Deprecated React `ui` overlay -- prefer behavior `drawUi`. Sits over the
|
|
1165
|
+
canvas and clips to the card. Behavior `ui` output lands in `.sceneUiLayer`,
|
|
1166
|
+
sized in card units and scaled onto the canvas box. */
|
|
1167
1167
|
.sceneUiRoot {
|
|
1168
1168
|
position: absolute;
|
|
1169
1169
|
inset: 0;
|
|
@@ -1477,9 +1477,10 @@
|
|
|
1477
1477
|
row, expanded leaves a smaller gap before the body. */
|
|
1478
1478
|
padding: 10px 16px 6px;
|
|
1479
1479
|
border-bottom: 0;
|
|
1480
|
-
/*
|
|
1481
|
-
the
|
|
1482
|
-
|
|
1480
|
+
/* pan-y: a vertical flick on the title / summary scrolls the inspector.
|
|
1481
|
+
Reorder lives on the grip (touch-action: none), not the whole row — that
|
|
1482
|
+
split is what lets scroll and reorder both work on phones. */
|
|
1483
|
+
touch-action: pan-y;
|
|
1483
1484
|
color: var(--castle-inspector-text);
|
|
1484
1485
|
font-size: 14px;
|
|
1485
1486
|
font-weight: 650;
|
|
@@ -1539,9 +1540,6 @@
|
|
|
1539
1540
|
font-weight: 400;
|
|
1540
1541
|
}
|
|
1541
1542
|
|
|
1542
|
-
/* Grab handle, left of the disclosure. `touch-action: none` is what makes the
|
|
1543
|
-
hold-then-drag possible on touch: without it the browser claims the gesture
|
|
1544
|
-
for scrolling before the hold completes and the drag never starts. */
|
|
1545
1543
|
/* The behavior's source file. Sits at the right end of the header row, inset
|
|
1546
1544
|
far enough to clear the remove button the inspector positions absolutely over
|
|
1547
1545
|
the panel's top-right corner. */
|
|
@@ -1640,28 +1638,37 @@
|
|
|
1640
1638
|
flex: 0 0 auto;
|
|
1641
1639
|
}
|
|
1642
1640
|
|
|
1643
|
-
/*
|
|
1644
|
-
|
|
1641
|
+
/* Drag handle for panel reorder. Owns the gesture (`touch-action: none`) so
|
|
1642
|
+
the browser does not steal it for scroll; the rest of the header stays
|
|
1643
|
+
pan-y. Hit target is larger than the glyph for fingers. */
|
|
1645
1644
|
.panelGrip {
|
|
1646
1645
|
display: inline-flex;
|
|
1647
1646
|
align-items: center;
|
|
1648
1647
|
justify-content: center;
|
|
1649
1648
|
flex: 0 0 auto;
|
|
1650
|
-
|
|
1651
|
-
|
|
1649
|
+
box-sizing: content-box;
|
|
1650
|
+
margin: -6px 0 -6px -6px;
|
|
1651
|
+
padding: 10px 8px;
|
|
1652
|
+
border: 0;
|
|
1653
|
+
background: none;
|
|
1654
|
+
/* Icon sizes itself in `em` via an inline style. */
|
|
1655
|
+
font-size: 11px;
|
|
1652
1656
|
color: var(--castle-inspector-muted);
|
|
1653
|
-
opacity: 0.
|
|
1657
|
+
opacity: 0.55;
|
|
1658
|
+
cursor: grab;
|
|
1659
|
+
touch-action: none;
|
|
1660
|
+
-webkit-user-select: none;
|
|
1661
|
+
user-select: none;
|
|
1654
1662
|
}
|
|
1655
1663
|
|
|
1656
|
-
.panelGrip:hover
|
|
1664
|
+
.panelGrip:hover,
|
|
1665
|
+
.panelGrip:focus-visible {
|
|
1657
1666
|
opacity: 1;
|
|
1667
|
+
color: var(--castle-text);
|
|
1658
1668
|
}
|
|
1659
1669
|
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
width on the svg. */
|
|
1663
|
-
.panelGrip {
|
|
1664
|
-
font-size: 9px;
|
|
1670
|
+
.panelGrip:active {
|
|
1671
|
+
cursor: grabbing;
|
|
1665
1672
|
}
|
|
1666
1673
|
|
|
1667
1674
|
/* Every behavior row. Positioned so the lifted one can be raised above its
|
|
@@ -2786,12 +2793,17 @@
|
|
|
2786
2793
|
linear-gradient(45deg, transparent 75%, #1a1a1a 75%),
|
|
2787
2794
|
linear-gradient(-45deg, transparent 75%, #1a1a1a 75%);
|
|
2788
2795
|
background-color: #121212;
|
|
2789
|
-
|
|
2796
|
+
/* The check travels with the artboard: PxArtEditor overrides --checker-size
|
|
2797
|
+
with the fit size times the current zoom, so a pinch scales the
|
|
2798
|
+
transparency pattern along with the art instead of re-tiling a fixed 16px
|
|
2799
|
+
grid underneath it. */
|
|
2800
|
+
--checker-size: 16px;
|
|
2801
|
+
background-size: var(--checker-size) var(--checker-size);
|
|
2790
2802
|
background-position:
|
|
2791
2803
|
0 0,
|
|
2792
|
-
0
|
|
2793
|
-
|
|
2794
|
-
-
|
|
2804
|
+
0 calc(var(--checker-size) / 2),
|
|
2805
|
+
calc(var(--checker-size) / 2) calc(var(--checker-size) / -2),
|
|
2806
|
+
calc(var(--checker-size) / -2) 0;
|
|
2795
2807
|
border: 1px solid var(--castle-inspector-border);
|
|
2796
2808
|
}
|
|
2797
2809
|
|
|
@@ -2803,6 +2815,19 @@
|
|
|
2803
2815
|
pointer-events: none;
|
|
2804
2816
|
}
|
|
2805
2817
|
|
|
2818
|
+
/* Behind the smooth canvas, so the path-layer snap lattice paints directly on
|
|
2819
|
+
the frame's own background and under everything drawn. Negative z-index
|
|
2820
|
+
children paint in z order after the element's background and before in-flow
|
|
2821
|
+
content, so -2 lands between the frame background and .drawingSmooth. */
|
|
2822
|
+
.drawingLattice {
|
|
2823
|
+
position: absolute;
|
|
2824
|
+
inset: 0;
|
|
2825
|
+
width: 100%;
|
|
2826
|
+
height: 100%;
|
|
2827
|
+
pointer-events: none;
|
|
2828
|
+
z-index: -2;
|
|
2829
|
+
}
|
|
2830
|
+
|
|
2806
2831
|
/* Behind the main canvas (negative z-index paints before static content in
|
|
2807
2832
|
the same containing block) — holds the corner-rounded render for "smooth"
|
|
2808
2833
|
sprites while the main canvas above it stays transparent except for tool
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
"@dnd-kit/modifiers": "^9.0.0",
|
|
16
16
|
"@dnd-kit/sortable": "^10.0.0",
|
|
17
17
|
"@dnd-kit/utilities": "^3.2.2",
|
|
18
|
-
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
|
19
18
|
"@lezer/highlight": "^1.2.3",
|
|
20
19
|
"castle-web-fonts": "^1.0.0",
|
|
21
20
|
"codemirror": "^6.0.2",
|
|
@@ -216,7 +215,6 @@
|
|
|
216
215
|
"resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz",
|
|
217
216
|
"integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==",
|
|
218
217
|
"license": "MIT",
|
|
219
|
-
"peer": true,
|
|
220
218
|
"dependencies": {
|
|
221
219
|
"@dnd-kit/accessibility": "^3.1.1",
|
|
222
220
|
"@dnd-kit/utilities": "^3.2.2",
|
|
@@ -411,29 +409,6 @@
|
|
|
411
409
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
|
412
410
|
}
|
|
413
411
|
},
|
|
414
|
-
"node_modules/@fortawesome/fontawesome-common-types": {
|
|
415
|
-
"version": "0.2.36",
|
|
416
|
-
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz",
|
|
417
|
-
"integrity": "sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg==",
|
|
418
|
-
"hasInstallScript": true,
|
|
419
|
-
"license": "MIT",
|
|
420
|
-
"engines": {
|
|
421
|
-
"node": ">=6"
|
|
422
|
-
}
|
|
423
|
-
},
|
|
424
|
-
"node_modules/@fortawesome/free-solid-svg-icons": {
|
|
425
|
-
"version": "5.15.4",
|
|
426
|
-
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.4.tgz",
|
|
427
|
-
"integrity": "sha512-JLmQfz6tdtwxoihXLg6lT78BorrFyCf59SAwBM6qV/0zXyVeDygJVb3fk+j5Qat+Yvcxp1buLTY5iDh1ZSAQ8w==",
|
|
428
|
-
"hasInstallScript": true,
|
|
429
|
-
"license": "(CC-BY-4.0 AND MIT)",
|
|
430
|
-
"dependencies": {
|
|
431
|
-
"@fortawesome/fontawesome-common-types": "^0.2.36"
|
|
432
|
-
},
|
|
433
|
-
"engines": {
|
|
434
|
-
"node": ">=6"
|
|
435
|
-
}
|
|
436
|
-
},
|
|
437
412
|
"node_modules/@humanfs/core": {
|
|
438
413
|
"version": "0.19.2",
|
|
439
414
|
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
|
|
@@ -670,7 +645,6 @@
|
|
|
670
645
|
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
|
|
671
646
|
"dev": true,
|
|
672
647
|
"license": "MIT",
|
|
673
|
-
"peer": true,
|
|
674
648
|
"bin": {
|
|
675
649
|
"acorn": "bin/acorn"
|
|
676
650
|
},
|
|
@@ -1131,7 +1105,6 @@
|
|
|
1131
1105
|
"integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==",
|
|
1132
1106
|
"dev": true,
|
|
1133
1107
|
"license": "MIT",
|
|
1134
|
-
"peer": true,
|
|
1135
1108
|
"dependencies": {
|
|
1136
1109
|
"@eslint-community/eslint-utils": "^4.8.0",
|
|
1137
1110
|
"@eslint-community/regexpp": "^4.12.1",
|
|
@@ -2441,7 +2414,6 @@
|
|
|
2441
2414
|
"resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz",
|
|
2442
2415
|
"integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==",
|
|
2443
2416
|
"license": "MIT",
|
|
2444
|
-
"peer": true,
|
|
2445
2417
|
"engines": {
|
|
2446
2418
|
"node": ">=0.10.0"
|
|
2447
2419
|
}
|
|
@@ -2451,7 +2423,6 @@
|
|
|
2451
2423
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz",
|
|
2452
2424
|
"integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==",
|
|
2453
2425
|
"license": "MIT",
|
|
2454
|
-
"peer": true,
|
|
2455
2426
|
"dependencies": {
|
|
2456
2427
|
"scheduler": "^0.27.0"
|
|
2457
2428
|
},
|
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
"behaviors"
|
|
17
17
|
],
|
|
18
18
|
"threshold": 0,
|
|
19
|
+
"ignore": [
|
|
20
|
+
"engine/icons.js"
|
|
21
|
+
],
|
|
19
22
|
"reporters": [
|
|
20
23
|
"consoleFull"
|
|
21
24
|
]
|
|
@@ -30,7 +33,6 @@
|
|
|
30
33
|
"@dnd-kit/modifiers": "^9.0.0",
|
|
31
34
|
"@dnd-kit/sortable": "^10.0.0",
|
|
32
35
|
"@dnd-kit/utilities": "^3.2.2",
|
|
33
|
-
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
|
34
36
|
"@lezer/highlight": "^1.2.3",
|
|
35
37
|
"castle-web-fonts": "^1.0.0",
|
|
36
38
|
"codemirror": "^6.0.2",
|
|
@@ -35,9 +35,6 @@ importers:
|
|
|
35
35
|
'@dnd-kit/utilities':
|
|
36
36
|
specifier: ^3.2.2
|
|
37
37
|
version: 3.2.2(react@19.2.7)
|
|
38
|
-
'@fortawesome/free-solid-svg-icons':
|
|
39
|
-
specifier: ^5.15.4
|
|
40
|
-
version: 5.15.4
|
|
41
38
|
'@lezer/highlight':
|
|
42
39
|
specifier: ^1.2.3
|
|
43
40
|
version: 1.2.3
|
|
@@ -186,14 +183,6 @@ packages:
|
|
|
186
183
|
resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==}
|
|
187
184
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
|
188
185
|
|
|
189
|
-
'@fortawesome/fontawesome-common-types@0.2.36':
|
|
190
|
-
resolution: {integrity: sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg==}
|
|
191
|
-
engines: {node: '>=6'}
|
|
192
|
-
|
|
193
|
-
'@fortawesome/free-solid-svg-icons@5.15.4':
|
|
194
|
-
resolution: {integrity: sha512-JLmQfz6tdtwxoihXLg6lT78BorrFyCf59SAwBM6qV/0zXyVeDygJVb3fk+j5Qat+Yvcxp1buLTY5iDh1ZSAQ8w==}
|
|
195
|
-
engines: {node: '>=6'}
|
|
196
|
-
|
|
197
186
|
'@humanfs/core@0.19.2':
|
|
198
187
|
resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==}
|
|
199
188
|
engines: {node: '>=18.18.0'}
|
|
@@ -447,6 +436,7 @@ packages:
|
|
|
447
436
|
eslint@9.39.4:
|
|
448
437
|
resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==}
|
|
449
438
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
|
439
|
+
deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options.
|
|
450
440
|
hasBin: true
|
|
451
441
|
peerDependencies:
|
|
452
442
|
jiti: '*'
|
|
@@ -1081,12 +1071,6 @@ snapshots:
|
|
|
1081
1071
|
'@eslint/core': 0.17.0
|
|
1082
1072
|
levn: 0.4.1
|
|
1083
1073
|
|
|
1084
|
-
'@fortawesome/fontawesome-common-types@0.2.36': {}
|
|
1085
|
-
|
|
1086
|
-
'@fortawesome/free-solid-svg-icons@5.15.4':
|
|
1087
|
-
dependencies:
|
|
1088
|
-
'@fortawesome/fontawesome-common-types': 0.2.36
|
|
1089
|
-
|
|
1090
1074
|
'@humanfs/core@0.19.2':
|
|
1091
1075
|
dependencies:
|
|
1092
1076
|
'@humanfs/types': 0.15.0
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
//
|
|
5
5
|
// Collection is remembered in the persistent store keyed by scene + actor id,
|
|
6
6
|
// so re-entering a scene doesn't respawn (and double-count) shards
|
|
7
|
-
// -- scene loads otherwise reset the world to its authored state.
|
|
7
|
+
// -- scene loads otherwise reset the world to its authored state. The store is
|
|
8
|
+
// a plain object, not a Set: `scene.persistent` has to survive JSON, since a
|
|
9
|
+
// multiplayer kit saves it per player.
|
|
8
10
|
function pickupKey(scene, actor) {
|
|
9
11
|
return `${scene.currentScenePath ?? ''}:${actor.id}`;
|
|
10
12
|
}
|
|
@@ -18,7 +20,7 @@ export class Pickup {
|
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
update(actor, scene, dt) {
|
|
21
|
-
if (scene.persistent?.collected?.
|
|
23
|
+
if (scene.persistent?.collected?.[pickupKey(scene, actor)]) {
|
|
22
24
|
scene.despawnActor(actor.id);
|
|
23
25
|
return;
|
|
24
26
|
}
|
|
@@ -33,7 +35,7 @@ export class Pickup {
|
|
|
33
35
|
if (!other.components.Player) return;
|
|
34
36
|
const per = (scene.persistent ??= {});
|
|
35
37
|
per.score = (per.score ?? 0) + 1;
|
|
36
|
-
(per.collected ??=
|
|
38
|
+
(per.collected ??= {})[pickupKey(scene, actor)] = true;
|
|
37
39
|
scene.despawnActor(actor.id);
|
|
38
40
|
}
|
|
39
41
|
}
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"ext": ".pxmodel",
|
|
43
43
|
"label": "Model",
|
|
44
44
|
"new": "New model",
|
|
45
|
-
"icon": "
|
|
45
|
+
"icon": "cube-transparent",
|
|
46
46
|
"editor": "kit",
|
|
47
47
|
"data": true
|
|
48
48
|
},
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"ext": ".jsx",
|
|
51
51
|
"label": "Behavior",
|
|
52
52
|
"new": "New behavior",
|
|
53
|
-
"icon": "code"
|
|
53
|
+
"icon": "file-code"
|
|
54
54
|
}
|
|
55
55
|
],
|
|
56
56
|
"defaultPlayFile": "scenes/main.scene"
|
|
@@ -58,16 +58,16 @@
|
|
|
58
58
|
"imports": {
|
|
59
59
|
"castle.physics-2d": {
|
|
60
60
|
"deckId": "ckRZGFW4iPrx",
|
|
61
|
-
"version": "2026-
|
|
61
|
+
"version": "2026-09-10T00:57:31.408Z"
|
|
62
62
|
},
|
|
63
63
|
"castle.base": {
|
|
64
64
|
"deckId": "yRcmH4_aYllE",
|
|
65
|
-
"version": "2026-09-
|
|
65
|
+
"version": "2026-09-10T00:56:59.388Z"
|
|
66
66
|
}
|
|
67
67
|
},
|
|
68
68
|
"main": "main.jsx",
|
|
69
69
|
"autoUpdateWhenImported": true,
|
|
70
70
|
"deckId": "JH0SclbPVP0y",
|
|
71
71
|
"cardId": "eXfAaUdbSU5A",
|
|
72
|
-
"publishedVersion": "2026-09-
|
|
72
|
+
"publishedVersion": "2026-09-10T20:10:28.916Z"
|
|
73
73
|
}
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
"@dnd-kit/modifiers": "^9.0.0",
|
|
17
17
|
"@dnd-kit/sortable": "^10.0.0",
|
|
18
18
|
"@dnd-kit/utilities": "^3.2.2",
|
|
19
|
-
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
|
20
19
|
"@lezer/highlight": "^1.2.3",
|
|
21
20
|
"castle-web-fonts": "^1.0.0",
|
|
22
21
|
"codemirror": "^6.0.2",
|
|
@@ -224,7 +223,6 @@
|
|
|
224
223
|
"resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz",
|
|
225
224
|
"integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==",
|
|
226
225
|
"license": "MIT",
|
|
227
|
-
"peer": true,
|
|
228
226
|
"dependencies": {
|
|
229
227
|
"@dnd-kit/accessibility": "^3.1.1",
|
|
230
228
|
"@dnd-kit/utilities": "^3.2.2",
|
|
@@ -419,29 +417,6 @@
|
|
|
419
417
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
|
420
418
|
}
|
|
421
419
|
},
|
|
422
|
-
"node_modules/@fortawesome/fontawesome-common-types": {
|
|
423
|
-
"version": "0.2.36",
|
|
424
|
-
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz",
|
|
425
|
-
"integrity": "sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg==",
|
|
426
|
-
"hasInstallScript": true,
|
|
427
|
-
"license": "MIT",
|
|
428
|
-
"engines": {
|
|
429
|
-
"node": ">=6"
|
|
430
|
-
}
|
|
431
|
-
},
|
|
432
|
-
"node_modules/@fortawesome/free-solid-svg-icons": {
|
|
433
|
-
"version": "5.15.4",
|
|
434
|
-
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.4.tgz",
|
|
435
|
-
"integrity": "sha512-JLmQfz6tdtwxoihXLg6lT78BorrFyCf59SAwBM6qV/0zXyVeDygJVb3fk+j5Qat+Yvcxp1buLTY5iDh1ZSAQ8w==",
|
|
436
|
-
"hasInstallScript": true,
|
|
437
|
-
"license": "(CC-BY-4.0 AND MIT)",
|
|
438
|
-
"dependencies": {
|
|
439
|
-
"@fortawesome/fontawesome-common-types": "^0.2.36"
|
|
440
|
-
},
|
|
441
|
-
"engines": {
|
|
442
|
-
"node": ">=6"
|
|
443
|
-
}
|
|
444
|
-
},
|
|
445
420
|
"node_modules/@humanfs/core": {
|
|
446
421
|
"version": "0.19.2",
|
|
447
422
|
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
|
|
@@ -678,7 +653,6 @@
|
|
|
678
653
|
"integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==",
|
|
679
654
|
"dev": true,
|
|
680
655
|
"license": "MIT",
|
|
681
|
-
"peer": true,
|
|
682
656
|
"bin": {
|
|
683
657
|
"acorn": "bin/acorn"
|
|
684
658
|
},
|
|
@@ -1139,7 +1113,6 @@
|
|
|
1139
1113
|
"integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==",
|
|
1140
1114
|
"dev": true,
|
|
1141
1115
|
"license": "MIT",
|
|
1142
|
-
"peer": true,
|
|
1143
1116
|
"dependencies": {
|
|
1144
1117
|
"@eslint-community/eslint-utils": "^4.8.0",
|
|
1145
1118
|
"@eslint-community/regexpp": "^4.12.1",
|
|
@@ -2449,7 +2422,6 @@
|
|
|
2449
2422
|
"resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz",
|
|
2450
2423
|
"integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==",
|
|
2451
2424
|
"license": "MIT",
|
|
2452
|
-
"peer": true,
|
|
2453
2425
|
"engines": {
|
|
2454
2426
|
"node": ">=0.10.0"
|
|
2455
2427
|
}
|
|
@@ -2459,7 +2431,6 @@
|
|
|
2459
2431
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz",
|
|
2460
2432
|
"integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==",
|
|
2461
2433
|
"license": "MIT",
|
|
2462
|
-
"peer": true,
|
|
2463
2434
|
"dependencies": {
|
|
2464
2435
|
"scheduler": "^0.27.0"
|
|
2465
2436
|
},
|
|
@@ -38,9 +38,6 @@ importers:
|
|
|
38
38
|
'@dnd-kit/utilities':
|
|
39
39
|
specifier: ^3.2.2
|
|
40
40
|
version: 3.2.2(react@19.2.8)
|
|
41
|
-
'@fortawesome/free-solid-svg-icons':
|
|
42
|
-
specifier: ^5.15.4
|
|
43
|
-
version: 5.15.4
|
|
44
41
|
'@lezer/highlight':
|
|
45
42
|
specifier: ^1.2.3
|
|
46
43
|
version: 1.2.3
|
|
@@ -195,14 +192,6 @@ packages:
|
|
|
195
192
|
resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==}
|
|
196
193
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
|
197
194
|
|
|
198
|
-
'@fortawesome/fontawesome-common-types@0.2.36':
|
|
199
|
-
resolution: {integrity: sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg==}
|
|
200
|
-
engines: {node: '>=6'}
|
|
201
|
-
|
|
202
|
-
'@fortawesome/free-solid-svg-icons@5.15.4':
|
|
203
|
-
resolution: {integrity: sha512-JLmQfz6tdtwxoihXLg6lT78BorrFyCf59SAwBM6qV/0zXyVeDygJVb3fk+j5Qat+Yvcxp1buLTY5iDh1ZSAQ8w==}
|
|
204
|
-
engines: {node: '>=6'}
|
|
205
|
-
|
|
206
195
|
'@humanfs/core@0.19.2':
|
|
207
196
|
resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==}
|
|
208
197
|
engines: {node: '>=18.18.0'}
|
|
@@ -1096,12 +1085,6 @@ snapshots:
|
|
|
1096
1085
|
'@eslint/core': 0.17.0
|
|
1097
1086
|
levn: 0.4.1
|
|
1098
1087
|
|
|
1099
|
-
'@fortawesome/fontawesome-common-types@0.2.36': {}
|
|
1100
|
-
|
|
1101
|
-
'@fortawesome/free-solid-svg-icons@5.15.4':
|
|
1102
|
-
dependencies:
|
|
1103
|
-
'@fortawesome/fontawesome-common-types': 0.2.36
|
|
1104
|
-
|
|
1105
1088
|
'@humanfs/core@0.19.2':
|
|
1106
1089
|
dependencies:
|
|
1107
1090
|
'@humanfs/types': 0.15.0
|
package/kits/real-time/CLAUDE.md
CHANGED
|
@@ -20,6 +20,16 @@ imports these modules from here directly.
|
|
|
20
20
|
- **A deck normally writes nothing against it.** The multiplayer kit it came with
|
|
21
21
|
already drives all of this; a deck's own code goes in `code/server/game.js` and
|
|
22
22
|
`code/client/game.js`, which that kit documents.
|
|
23
|
+
- **What persists.** Object poses, the ids of scene actors a client despawned,
|
|
24
|
+
each player's last pose and state block by account, and whatever the optional
|
|
25
|
+
`save(sim)` hook returns. Written every ten seconds when something moved and
|
|
26
|
+
at a clean shutdown. Nothing to configure.
|
|
27
|
+
- **A returning player starts where they left off.** A second connection from
|
|
28
|
+
the same account while the first is still playing gets a new character at the
|
|
29
|
+
spawn. The room is `session.sessionId`; every `public` shard shares one.
|
|
30
|
+
- `restore(sim, saved)` receives the last `save` result before `ready`. Storage
|
|
31
|
+
is keyed by deck, so the deck must be published; `castle-web serve` brokers it
|
|
32
|
+
as the deck's creator.
|
|
23
33
|
- A pose is an opaque array of numbers here, so anything reading inside one takes
|
|
24
34
|
the kit's `code/client/poses.js` as an argument. That is the seam to use when
|
|
25
35
|
something genuinely needs a lower level.
|
|
@@ -59,10 +69,19 @@ never learns the format.
|
|
|
59
69
|
values of a player pose are geometry before the `clamped` flag, and `epsilonAt`,
|
|
60
70
|
which a kit whose pose values are all one unit leaves undefined.
|
|
61
71
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
72
|
+
Persistence adds to that contract: `world.restorePoses(sim, poses)` puts saved
|
|
73
|
+
poses back on the bodies the scene still has, and `players.addPlayer` takes the
|
|
74
|
+
saved pose a returning player starts from. Optional beside those:
|
|
75
|
+
`world.removeActor(sim, id)` drops a despawned actor's body, and
|
|
76
|
+
`players.setState` / `players.stateOf` keep the block a client reports.
|
|
77
|
+
|
|
78
|
+
Two files here touch the DOM, both dependency-free. `soloBadge.js` is a fixed
|
|
79
|
+
badge that names why a session fell back to solo (`status().soloReason` from
|
|
80
|
+
`connection.js`), drawn by both kits each frame through `updateSoloBadge`; a
|
|
81
|
+
deck's `soloBadge` hook hides it. `joinOverlay.js` covers the card with
|
|
82
|
+
"Joining…" from the first frame until the session's first snapshot places the
|
|
83
|
+
player, so nobody plays from the scene's spawn before the saved spot arrives;
|
|
84
|
+
it gives up after ten seconds with a console warning.
|
|
66
85
|
|
|
67
86
|
## Rules for editing this kit
|
|
68
87
|
|
|
@@ -81,7 +81,8 @@ export async function connectSession({ onLog = () => {} } = {}) {
|
|
|
81
81
|
// the transport handles every dimensional format in the same way.
|
|
82
82
|
// The client system calls this every frame; most calls only accumulate the
|
|
83
83
|
// ownership requests, which are held until the next rate-limited send.
|
|
84
|
-
sendMove: (pose, owned, claims, releases) =>
|
|
84
|
+
sendMove: (pose, owned, claims, releases, state) =>
|
|
85
|
+
sendMove(net, pose, owned, claims, releases, state),
|
|
85
86
|
|
|
86
87
|
// Send deck-specific data. The server routes these to `code/server/game.js`.
|
|
87
88
|
send: (data) => net.connection.send(data),
|
|
@@ -106,8 +107,10 @@ export async function connectSession({ onLog = () => {} } = {}) {
|
|
|
106
107
|
};
|
|
107
108
|
}
|
|
108
109
|
|
|
109
|
-
// Collect ownership requests from every frame and send at `MOVE_HZ`.
|
|
110
|
-
|
|
110
|
+
// Collect ownership requests from every frame and send at `MOVE_HZ`. `state` is
|
|
111
|
+
// the player's own block, sent along when the caller has one to send. Returns
|
|
112
|
+
// whether a packet went out.
|
|
113
|
+
function sendMove(net, pose, owned, claims, releases, state) {
|
|
111
114
|
// Gathered on every frame, including the ones that send nothing, so a claim
|
|
112
115
|
// made in between is still in the next message. The sets also collapse
|
|
113
116
|
// repeated requests for the same object over that interval.
|
|
@@ -119,7 +122,7 @@ function sendMove(net, pose, owned, claims, releases) {
|
|
|
119
122
|
}
|
|
120
123
|
const now = performance.now();
|
|
121
124
|
if (now - net.sentAt < SEND_MS) {
|
|
122
|
-
return;
|
|
125
|
+
return false;
|
|
123
126
|
}
|
|
124
127
|
net.sentAt = now;
|
|
125
128
|
|
|
@@ -130,9 +133,11 @@ function sendMove(net, pose, owned, claims, releases) {
|
|
|
130
133
|
c: [...net.claims],
|
|
131
134
|
r: [...net.releases],
|
|
132
135
|
o: owned,
|
|
136
|
+
...(state === undefined ? {} : { s: state }),
|
|
133
137
|
});
|
|
134
138
|
|
|
135
139
|
// Clear only after a packet; rate-limited returns above retain the requests.
|
|
136
140
|
net.claims.clear();
|
|
137
141
|
net.releases.clear();
|
|
142
|
+
return true;
|
|
138
143
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// A full-card overlay shown from connecting until the server's first snapshot
|
|
2
|
+
// places this player. Under it the local character may still be standing at the
|
|
3
|
+
// scene's spawn; the overlay hides that and takes the pointer, so nothing is
|
|
4
|
+
// played until the session says where things are.
|
|
5
|
+
//
|
|
6
|
+
// It mounts inside the card when the sdk has marked one, so a capture of the
|
|
7
|
+
// card (a cover, a playtest frame) includes it; otherwise it covers the page.
|
|
8
|
+
//
|
|
9
|
+
// Dependency-free DOM, like the solo badge: the kits draw their scenes
|
|
10
|
+
// differently and share no HUD.
|
|
11
|
+
|
|
12
|
+
let element = null;
|
|
13
|
+
|
|
14
|
+
// Show or hide the overlay. Idempotent; cheap enough to call every frame.
|
|
15
|
+
export function showJoinOverlay(visible) {
|
|
16
|
+
if (typeof document === 'undefined') {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (!visible) {
|
|
20
|
+
element?.remove();
|
|
21
|
+
element = null;
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (element) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const card = document.querySelector('#castle-card, [data-castle-card]');
|
|
28
|
+
if (card && getComputedStyle(card).position === 'static') {
|
|
29
|
+
card.style.position = 'relative';
|
|
30
|
+
}
|
|
31
|
+
element = document.createElement('div');
|
|
32
|
+
element.setAttribute('data-castle-join-overlay', '');
|
|
33
|
+
element.style.cssText = [
|
|
34
|
+
card ? 'position:absolute' : 'position:fixed',
|
|
35
|
+
'inset:0',
|
|
36
|
+
'display:flex',
|
|
37
|
+
'align-items:center',
|
|
38
|
+
'justify-content:center',
|
|
39
|
+
'background:#0a0a0a',
|
|
40
|
+
'color:#fff',
|
|
41
|
+
'font:500 15px/1.4 system-ui,sans-serif',
|
|
42
|
+
'z-index:2147483646',
|
|
43
|
+
].join(';');
|
|
44
|
+
element.textContent = 'Joining…';
|
|
45
|
+
(card ?? document.body).appendChild(element);
|
|
46
|
+
}
|
|
@@ -15,6 +15,10 @@ export const MOVE = 'i';
|
|
|
15
15
|
export const WORLD = 'w';
|
|
16
16
|
export const STATE = 's';
|
|
17
17
|
|
|
18
|
+
// A client reports that it removed a scene actor: `{ k: GONE, id }`. The
|
|
19
|
+
// session removes it for everyone, for good.
|
|
20
|
+
export const GONE = 'g';
|
|
21
|
+
|
|
18
22
|
// Movement reports run below the render rate and below the platform's roughly
|
|
19
23
|
// 30-message-per-second client cap. A second report inside one server tick would
|
|
20
24
|
// be overwritten before the simulation read it.
|
|
@@ -21,8 +21,12 @@ const bodyModules = {
|
|
|
21
21
|
// `session.js` receives this value from the dimensional kit's server entry and
|
|
22
22
|
// calls the hooks at the stages listed below.
|
|
23
23
|
//
|
|
24
|
+
// restore(sim, saved) the value the last `save` returned for this
|
|
25
|
+
// room, or null. Runs before `ready`
|
|
24
26
|
// ready(sim) after the world and its scene bodies exist,
|
|
25
27
|
// before the first server tick
|
|
28
|
+
// save(sim) JSON kept for this room, written with the
|
|
29
|
+
// world every ten seconds and at shutdown
|
|
26
30
|
// message(session, player, d) client data that is not a pose report. It
|
|
27
31
|
// receives no handover list, so a world change
|
|
28
32
|
// is kept and applied later by `place` or `step`
|