castle-web-cli 0.4.168 → 0.4.170
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.js +17 -0
- package/dist/agent.js +23 -13
- package/dist/atomicFile.d.ts +29 -0
- package/dist/atomicFile.js +120 -0
- package/dist/castle-host/host.js +37 -0
- package/dist/get-deck.js +2 -11
- package/dist/headlessCover.d.ts +4 -0
- package/dist/headlessCover.js +7 -5
- package/dist/ide.js +14 -6
- 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 +51 -74
- 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-BvQmVwlO.css +1 -0
- package/dist/shell/assets/index-CV5sBby1.js +445 -0
- package/dist/shell/index.html +2 -2
- 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 +66 -1
- package/kits/base/sdk/commands.d.ts +23 -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/multiplayer-2d/castle.json +3 -3
- package/kits/multiplayer-2d/package-lock.json +0 -27
- package/kits/multiplayer-2d/package.json +0 -1
- package/kits/multiplayer-3d/castle.json +4 -4
- package/kits/multiplayer-3d/package-lock.json +0 -27
- package/kits/multiplayer-3d/package.json +0 -1
- 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 +83 -180
- 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/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/turn-based/castle.json +3 -3
- package/kits/turn-based/package-lock.json +0 -27
- package/kits/turn-based/package.json +0 -1
- package/package.json +5 -4
- package/dist/shell/assets/index-CVHj503j.css +0 -1
- package/dist/shell/assets/index-D-qJ5VGp.js +0 -425
- package/kits/blank/.castle/agent/children.json +0 -1
- package/kits/blank/.castle/agent/messages.json +0 -9
- package/kits/blank/.castle/agent/pending-sends.json +0 -1
- package/kits/blank/.castle/agent/tasks/index.md +0 -2
- package/kits/blank/.castle/docs/platform.md +0 -36
- package/kits/blank/node_modules/.vite/deps/_metadata.json +0 -8
- package/kits/blank/node_modules/.vite/deps/package.json +0 -3
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Generated by scripts/build-icons.mjs from @phosphor-icons/core regular SVGs.
|
|
2
|
+
// Do not edit. Run `npm run icons` to regenerate.
|
|
3
|
+
|
|
4
|
+
export const icons = {
|
|
5
|
+
bars: { icon: [256, 256, [], '', "M224,128a8,8,0,0,1-8,8H40a8,8,0,0,1,0-16H216A8,8,0,0,1,224,128ZM40,72H216a8,8,0,0,0,0-16H40a8,8,0,0,0,0,16ZM216,184H40a8,8,0,0,0,0,16H216a8,8,0,0,0,0-16Z"] },
|
|
6
|
+
"bezier-curve": { icon: [256, 256, [], '', "M221.07,144.41A96.68,96.68,0,0,0,181,88h59a8,8,0,0,0,0-16H159a32,32,0,0,0-62,0H16a8,8,0,0,0,0,16H75a96.68,96.68,0,0,0-40.07,56.41A32,32,0,1,0,51.08,146,80.6,80.6,0,0,1,99,93.44a32,32,0,0,0,58.06,0A80.6,80.6,0,0,1,204.92,146a32,32,0,1,0,16.15-1.57ZM56,176a16,16,0,1,1-16-16A16,16,0,0,1,56,176Zm72-80a16,16,0,1,1,16-16A16,16,0,0,1,128,96Zm88,96a16,16,0,1,1,16-16A16,16,0,0,1,216,192Z"] },
|
|
7
|
+
"bounding-box": { icon: [256, 256, [], '', "M208,96a16,16,0,0,0,16-16V48a16,16,0,0,0-16-16H176a16,16,0,0,0-16,16v8H96V48A16,16,0,0,0,80,32H48A16,16,0,0,0,32,48V80A16,16,0,0,0,48,96h8v64H48a16,16,0,0,0-16,16v32a16,16,0,0,0,16,16H80a16,16,0,0,0,16-16v-8h64v8a16,16,0,0,0,16,16h32a16,16,0,0,0,16-16V176a16,16,0,0,0-16-16h-8V96ZM176,48h32V80H176ZM48,48H80V63.9a.51.51,0,0,0,0,.2V80H48ZM80,208H48V176H80v15.9a.51.51,0,0,0,0,.2V208Zm128,0H176V176h32Zm-24-48h-8a16,16,0,0,0-16,16v8H96v-8a16,16,0,0,0-16-16H72V96h8A16,16,0,0,0,96,80V72h64v8a16,16,0,0,0,16,16h8Z"] },
|
|
8
|
+
check: { icon: [256, 256, [], '', "M229.66,77.66l-128,128a8,8,0,0,1-11.32,0l-56-56a8,8,0,0,1,11.32-11.32L96,188.69,218.34,66.34a8,8,0,0,1,11.32,11.32Z"] },
|
|
9
|
+
"chevron-down": { icon: [256, 256, [], '', "M213.66,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,53.66,90.34L128,164.69l74.34-74.35a8,8,0,0,1,11.32,11.32Z"] },
|
|
10
|
+
"chevron-left": { icon: [256, 256, [], '', "M165.66,202.34a8,8,0,0,1-11.32,11.32l-80-80a8,8,0,0,1,0-11.32l80-80a8,8,0,0,1,11.32,11.32L91.31,128Z"] },
|
|
11
|
+
"chevron-right": { icon: [256, 256, [], '', "M181.66,133.66l-80,80a8,8,0,0,1-11.32-11.32L164.69,128,90.34,53.66a8,8,0,0,1,11.32-11.32l80,80A8,8,0,0,1,181.66,133.66Z"] },
|
|
12
|
+
"chevron-up": { icon: [256, 256, [], '', "M213.66,165.66a8,8,0,0,1-11.32,0L128,91.31,53.66,165.66a8,8,0,0,1-11.32-11.32l80-80a8,8,0,0,1,11.32,0l80,80A8,8,0,0,1,213.66,165.66Z"] },
|
|
13
|
+
circle: { icon: [256, 256, [], '', "M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Z"] },
|
|
14
|
+
checkerboard: { icon: [256, 256, [], '', "M208,32H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32Zm-12.69,88L136,60.69V48h12.69L208,107.32V120ZM136,83.31,172.69,120H136Zm72,1.38L171.31,48H208ZM120,48v72H48V48ZM107.31,208,48,148.69V136H60.69L120,195.31V208ZM120,172.69,83.31,136H120Zm-72-1.38L84.69,208H48ZM208,208H136V136h72v72Z"] },
|
|
15
|
+
clone: { icon: [256, 256, [], '', "M216,32H88a8,8,0,0,0-8,8V80H40a8,8,0,0,0-8,8V216a8,8,0,0,0,8,8H168a8,8,0,0,0,8-8V176h40a8,8,0,0,0,8-8V40A8,8,0,0,0,216,32ZM160,208H48V96H160Zm48-48H176V88a8,8,0,0,0-8-8H96V48H208Z"] },
|
|
16
|
+
"code-fork": { icon: [256, 256, [], '', "M224,64a32,32,0,1,0-40,31v17a8,8,0,0,1-8,8H80a8,8,0,0,1-8-8V95a32,32,0,1,0-16,0v17a24,24,0,0,0,24,24h40v25a32,32,0,1,0,16,0V136h40a24,24,0,0,0,24-24V95A32.06,32.06,0,0,0,224,64ZM48,64A16,16,0,1,1,64,80,16,16,0,0,1,48,64Zm96,128a16,16,0,1,1-16-16A16,16,0,0,1,144,192ZM192,80a16,16,0,1,1,16-16A16,16,0,0,1,192,80Z"] },
|
|
17
|
+
"dot-circle": { icon: [256, 256, [], '', "M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm0-144a56,56,0,1,0,56,56A56.06,56.06,0,0,0,128,72Zm0,96a40,40,0,1,1,40-40A40,40,0,0,1,128,168Z"] },
|
|
18
|
+
eraser: { icon: [256, 256, [], '', "M225,80.4,183.6,39a24,24,0,0,0-33.94,0L31,157.66a24,24,0,0,0,0,33.94l30.06,30.06A8,8,0,0,0,66.74,224H216a8,8,0,0,0,0-16h-84.7L225,114.34A24,24,0,0,0,225,80.4ZM108.68,208H70.05L42.33,180.28a8,8,0,0,1,0-11.31L96,115.31,148.69,168Zm105-105L160,156.69,107.31,104,161,50.34a8,8,0,0,1,11.32,0l41.38,41.38a8,8,0,0,1,0,11.31Z"] },
|
|
19
|
+
eye: { icon: [256, 256, [], '', "M247.31,124.76c-.35-.79-8.82-19.58-27.65-38.41C194.57,61.26,162.88,48,128,48S61.43,61.26,36.34,86.35C17.51,105.18,9,124,8.69,124.76a8,8,0,0,0,0,6.5c.35.79,8.82,19.57,27.65,38.4C61.43,194.74,93.12,208,128,208s66.57-13.26,91.66-38.34c18.83-18.83,27.3-37.61,27.65-38.4A8,8,0,0,0,247.31,124.76ZM128,192c-30.78,0-57.67-11.19-79.93-33.25A133.47,133.47,0,0,1,25,128,133.33,133.33,0,0,1,48.07,97.25C70.33,75.19,97.22,64,128,64s57.67,11.19,79.93,33.25A133.46,133.46,0,0,1,231.05,128C223.84,141.46,192.43,192,128,192Zm0-112a48,48,0,1,0,48,48A48.05,48.05,0,0,0,128,80Zm0,80a32,32,0,1,1,32-32A32,32,0,0,1,128,160Z"] },
|
|
20
|
+
"eye-closed": { icon: [256, 256, [], '', "M228,175a8,8,0,0,1-10.92-3l-19-33.2A123.23,123.23,0,0,1,162,155.46l5.87,35.22a8,8,0,0,1-6.58,9.21A8.4,8.4,0,0,1,160,200a8,8,0,0,1-7.88-6.69l-5.77-34.58a133.06,133.06,0,0,1-36.68,0l-5.77,34.58A8,8,0,0,1,96,200a8.4,8.4,0,0,1-1.32-.11,8,8,0,0,1-6.58-9.21L94,155.46a123.23,123.23,0,0,1-36.06-16.69L39,172A8,8,0,1,1,25.06,164l20-35a153.47,153.47,0,0,1-19.3-20A8,8,0,1,1,38.22,99c16.6,20.54,45.64,45,89.78,45s73.18-24.49,89.78-45A8,8,0,1,1,230.22,109a153.47,153.47,0,0,1-19.3,20l20,35A8,8,0,0,1,228,175Z"] },
|
|
21
|
+
eyedropper: { icon: [256, 256, [], '', "M224,67.3a35.79,35.79,0,0,0-11.26-25.66c-14-13.28-36.72-12.78-50.62,1.13L142.8,62.2a24,24,0,0,0-33.14.77l-9,9a16,16,0,0,0,0,22.64l2,2.06-51,51a39.75,39.75,0,0,0-10.53,38l-8,18.41A13.68,13.68,0,0,0,36,219.3a15.92,15.92,0,0,0,17.71,3.35L71.23,215a39.89,39.89,0,0,0,37.06-10.75l51-51,2.06,2.06a16,16,0,0,0,22.62,0l9-9a24,24,0,0,0,.74-33.18l19.75-19.87A35.75,35.75,0,0,0,224,67.3ZM97,193a24,24,0,0,1-24,6,8,8,0,0,0-5.55.31l-18.1,7.91L57,189.41a8,8,0,0,0,.25-5.75A23.88,23.88,0,0,1,63,159l51-51,33.94,34ZM202.13,82l-25.37,25.52a8,8,0,0,0,0,11.3l4.89,4.89a8,8,0,0,1,0,11.32l-9,9L112,83.26l9-9a8,8,0,0,1,11.31,0l4.89,4.89a8,8,0,0,0,11.33,0l24.94-25.09c7.81-7.82,20.5-8.18,28.29-.81a20,20,0,0,1,.39,28.7Z"] },
|
|
22
|
+
fill: { icon: [256, 256, [], '', "M234.53,139.07a8,8,0,0,0,3.13-13.24L122.17,10.34a8,8,0,0,0-11.31,0L70.25,51,45.65,26.34A8,8,0,0,0,34.34,37.66l24.6,24.6L15,106.17a24,24,0,0,0,0,33.94L99.89,225a24,24,0,0,0,33.94,0l78.49-78.49Zm-32.19-5.24-79.83,79.83a8,8,0,0,1-11.31,0L26.34,128.8a8,8,0,0,1,0-11.31L70.25,73.57l29.12,29.12a28,28,0,1,0,11.31-11.32L81.57,62.26l35-34.95L217.19,128l-11.72,3.9A8.09,8.09,0,0,0,202.34,133.83Zm-86.83-26.31,0,0a13.26,13.26,0,1,1-.05.06S115.51,107.53,115.51,107.52Zm123.15,56a8,8,0,0,0-13.32,0C223.57,166.23,208,190.09,208,208a24,24,0,0,0,48,0C256,190.09,240.43,166.23,238.66,163.56ZM232,216a8,8,0,0,1-8-8c0-6.8,4-16.32,8-24.08,4,7.76,8,17.34,8,24.08A8,8,0,0,1,232,216Z"] },
|
|
23
|
+
film: { icon: [256, 256, [], '', "M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40ZM40,88h80v80H40Zm96-16V56h32V72Zm-16,0H88V56h32Zm0,112v16H88V184Zm16,0h32v16H136Zm0-16V88h80v80Zm80-96H184V56h32ZM72,56V72H40V56ZM40,184H72v16H40Zm176,16H184V184h32v16Z"] },
|
|
24
|
+
fit: { icon: [256, 256, [], '', "M216,48V88a8,8,0,0,1-16,0V56H168a8,8,0,0,1,0-16h40A8,8,0,0,1,216,48ZM88,200H56V168a8,8,0,0,0-16,0v40a8,8,0,0,0,8,8H88a8,8,0,0,0,0-16Zm120-40a8,8,0,0,0-8,8v32H168a8,8,0,0,0,0,16h40a8,8,0,0,0,8-8V168A8,8,0,0,0,208,160ZM88,40H48a8,8,0,0,0-8,8V88a8,8,0,0,0,16,0V56H88a8,8,0,0,0,0-16Z"] },
|
|
25
|
+
"flip-h": { icon: [256, 256, [], '', "M107.18,24.33a15.86,15.86,0,0,0-17.92,9.45l-.06.14-64,159.93A16,16,0,0,0,40,216h64a16,16,0,0,0,16-16V40A15.85,15.85,0,0,0,107.18,24.33ZM104,200H40l.06-.15L104,40Zm126.77-6.15-64-159.93-.06-.14A16,16,0,0,0,136,40V200a16,16,0,0,0,16,16h64a16,16,0,0,0,14.78-22.15ZM152,200V40l63.93,159.84.06.15Z"] },
|
|
26
|
+
"flip-v": { icon: [256, 256, [], '', "M56,120H216a16,16,0,0,0,6.23-30.74l-.14-.06-159.93-64A16,16,0,0,0,40,40v64A16,16,0,0,0,56,120Zm0-80,.15.06L216,104H56l0-64Zm160,96H56a16,16,0,0,0-16,16v64a16,16,0,0,0,22.15,14.78l159.93-64,.14-.06A16,16,0,0,0,216,136ZM56.15,215.93,56,216V152H216Z"] },
|
|
27
|
+
grip: { icon: [256, 256, [], '', "M104,60A12,12,0,1,1,92,48,12,12,0,0,1,104,60Zm60,12a12,12,0,1,0-12-12A12,12,0,0,0,164,72ZM92,116a12,12,0,1,0,12,12A12,12,0,0,0,92,116Zm72,0a12,12,0,1,0,12,12A12,12,0,0,0,164,116ZM92,184a12,12,0,1,0,12,12A12,12,0,0,0,92,184Zm72,0a12,12,0,1,0,12,12A12,12,0,0,0,164,184Z"] },
|
|
28
|
+
image: { icon: [256, 256, [], '', "M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40Zm0,16V158.75l-26.07-26.06a16,16,0,0,0-22.63,0l-20,20-44-44a16,16,0,0,0-22.62,0L40,149.37V56ZM40,172l52-52,80,80H40Zm176,28H194.63l-36-36,20-20L216,181.38V200ZM144,100a12,12,0,1,1,12,12A12,12,0,0,1,144,100Z"] },
|
|
29
|
+
"layer-group": { icon: [256, 256, [], '', "M230.91,172A8,8,0,0,1,228,182.91l-96,56a8,8,0,0,1-8.06,0l-96-56A8,8,0,0,1,36,169.09l92,53.65,92-53.65A8,8,0,0,1,230.91,172ZM220,121.09l-92,53.65L36,121.09A8,8,0,0,0,28,134.91l96,56a8,8,0,0,0,8.06,0l96-56A8,8,0,1,0,220,121.09ZM24,80a8,8,0,0,1,4-6.91l96-56a8,8,0,0,1,8.06,0l96,56a8,8,0,0,1,0,13.82l-96,56a8,8,0,0,1-8.06,0l-96-56A8,8,0,0,1,24,80Zm23.88,0L128,126.74,208.12,80,128,33.26Z"] },
|
|
30
|
+
link: { icon: [256, 256, [], '', "M240,88.23a54.43,54.43,0,0,1-16,37L189.25,160a54.27,54.27,0,0,1-38.63,16h-.05A54.63,54.63,0,0,1,96,119.84a8,8,0,0,1,16,.45A38.62,38.62,0,0,0,150.58,160h0a38.39,38.39,0,0,0,27.31-11.31l34.75-34.75a38.63,38.63,0,0,0-54.63-54.63l-11,11A8,8,0,0,1,135.7,59l11-11A54.65,54.65,0,0,1,224,48,54.86,54.86,0,0,1,240,88.23ZM109,185.66l-11,11A38.41,38.41,0,0,1,70.6,208h0a38.63,38.63,0,0,1-27.29-65.94L78,107.31A38.63,38.63,0,0,1,144,135.71a8,8,0,0,0,16,.45A54.86,54.86,0,0,0,144,96a54.65,54.65,0,0,0-77.27,0L32,130.75A54.62,54.62,0,0,0,70.56,224h0a54.28,54.28,0,0,0,38.64-16l11-11A8,8,0,0,0,109,185.66Z"] },
|
|
31
|
+
marquee: { icon: [256, 256, [], '', "M152,40a8,8,0,0,1-8,8H112a8,8,0,0,1,0-16h32A8,8,0,0,1,152,40Zm-8,168H112a8,8,0,0,0,0,16h32a8,8,0,0,0,0-16ZM208,32H184a8,8,0,0,0,0,16h24V72a8,8,0,0,0,16,0V48A16,16,0,0,0,208,32Zm8,72a8,8,0,0,0-8,8v32a8,8,0,0,0,16,0V112A8,8,0,0,0,216,104Zm0,72a8,8,0,0,0-8,8v24H184a8,8,0,0,0,0,16h24a16,16,0,0,0,16-16V184A8,8,0,0,0,216,176ZM40,152a8,8,0,0,0,8-8V112a8,8,0,0,0-16,0v32A8,8,0,0,0,40,152Zm32,56H48V184a8,8,0,0,0-16,0v24a16,16,0,0,0,16,16H72a8,8,0,0,0,0-16ZM72,32H48A16,16,0,0,0,32,48V72a8,8,0,0,0,16,0V48H72a8,8,0,0,0,0-16Z"] },
|
|
32
|
+
move: { icon: [256, 256, [], '', "M90.34,61.66a8,8,0,0,1,0-11.32l32-32a8,8,0,0,1,11.32,0l32,32a8,8,0,0,1-11.32,11.32L136,43.31V96a8,8,0,0,1-16,0V43.31L101.66,61.66A8,8,0,0,1,90.34,61.66Zm64,132.68L136,212.69V160a8,8,0,0,0-16,0v52.69l-18.34-18.35a8,8,0,0,0-11.32,11.32l32,32a8,8,0,0,0,11.32,0l32-32a8,8,0,0,0-11.32-11.32Zm83.32-72-32-32a8,8,0,0,0-11.32,11.32L212.69,120H160a8,8,0,0,0,0,16h52.69l-18.35,18.34a8,8,0,0,0,11.32,11.32l32-32A8,8,0,0,0,237.66,122.34ZM43.31,136H96a8,8,0,0,0,0-16H43.31l18.35-18.34A8,8,0,0,0,50.34,90.34l-32,32a8,8,0,0,0,0,11.32l32,32a8,8,0,0,0,11.32-11.32Z"] },
|
|
33
|
+
"navigation-arrow": { icon: [256, 256, [], '', "M237.33,106.21,61.41,41l-.16-.05A16,16,0,0,0,40.9,61.25a1,1,0,0,0,.05.16l65.26,175.92A15.77,15.77,0,0,0,121.28,248h.3a15.77,15.77,0,0,0,15-11.29l.06-.2,21.84-78,78-21.84.2-.06a16,16,0,0,0,.62-30.38ZM149.84,144.3a8,8,0,0,0-5.54,5.54L121.3,232l-.06-.17L56,56l175.82,65.22.16.06Z"] },
|
|
34
|
+
"object-group": { icon: [256, 256, [], '', "M152,40a8,8,0,0,1-8,8H112a8,8,0,0,1,0-16h32A8,8,0,0,1,152,40Zm-8,168H112a8,8,0,0,0,0,16h32a8,8,0,0,0,0-16ZM208,48V72a8,8,0,0,0,16,0V48a16,16,0,0,0-16-16H184a8,8,0,0,0,0,16Zm8,56a8,8,0,0,0-8,8v32a8,8,0,0,0,16,0V112A8,8,0,0,0,216,104ZM40,152a8,8,0,0,0,8-8V112a8,8,0,0,0-16,0v32A8,8,0,0,0,40,152Zm32,56H48V184a8,8,0,0,0-16,0v24a16,16,0,0,0,16,16H72a8,8,0,0,0,0-16ZM72,32H48A16,16,0,0,0,32,48V72a8,8,0,0,0,16,0V48H72a8,8,0,0,0,0-16ZM240,208H224V192a8,8,0,0,0-16,0v16H192a8,8,0,0,0,0,16h16v16a8,8,0,0,0,16,0V224h16a8,8,0,0,0,0-16Z"] },
|
|
35
|
+
pencil: { icon: [256, 256, [], '', "M227.31,73.37,182.63,28.68a16,16,0,0,0-22.63,0L36.69,152A15.86,15.86,0,0,0,32,163.31V208a16,16,0,0,0,16,16H92.69A15.86,15.86,0,0,0,104,219.31L227.31,96a16,16,0,0,0,0-22.63ZM92.69,208H48V163.31l88-88L180.69,120ZM192,108.68,147.31,64l24-24L216,84.68Z"] },
|
|
36
|
+
"pen-nib": { icon: [256, 256, [], '', "M248,92.68a15.86,15.86,0,0,0-4.69-11.31L174.63,12.68a16,16,0,0,0-22.63,0L123.57,41.11l-58,21.77A16.06,16.06,0,0,0,55.35,75.23L32.11,214.68A8,8,0,0,0,40,224a8.4,8.4,0,0,0,1.32-.11l139.44-23.24a16,16,0,0,0,12.35-10.17l21.77-58L243.31,104A15.87,15.87,0,0,0,248,92.68Zm-69.87,92.19L63.32,204l47.37-47.37a28,28,0,1,0-11.32-11.32L52,192.7,71.13,77.86,126,57.29,198.7,130ZM112,132a12,12,0,1,1,12,12A12,12,0,0,1,112,132Zm96-15.32L139.31,48l24-24L232,92.68Z"] },
|
|
37
|
+
play: { icon: [256, 256, [], '', "M232.4,114.49,88.32,26.35a16,16,0,0,0-16.2-.3A15.86,15.86,0,0,0,64,39.87V216.13A15.94,15.94,0,0,0,80,232a16.07,16.07,0,0,0,8.36-2.35L232.4,141.51a15.81,15.81,0,0,0,0-27ZM80,215.94V40l143.83,88Z"] },
|
|
38
|
+
plus: { icon: [256, 256, [], '', "M224,128a8,8,0,0,1-8,8H136v80a8,8,0,0,1-16,0V136H40a8,8,0,0,1,0-16h80V40a8,8,0,0,1,16,0v80h80A8,8,0,0,1,224,128Z"] },
|
|
39
|
+
redo: { icon: [256, 256, [], '', "M170.34,130.34,204.69,96H88a48,48,0,0,0,0,96h88a8,8,0,0,1,0,16H88A64,64,0,0,1,88,80H204.69L170.34,45.66a8,8,0,0,1,11.32-11.32l48,48a8,8,0,0,1,0,11.32l-48,48a8,8,0,0,1-11.32-11.32Z"] },
|
|
40
|
+
rotate: { icon: [256, 256, [], '', "M240,56v48a8,8,0,0,1-8,8H184a8,8,0,0,1,0-16H211.4L184.81,71.64l-.25-.24a80,80,0,1,0-1.67,114.78,8,8,0,0,1,11,11.63A95.44,95.44,0,0,1,128,224h-1.32A96,96,0,1,1,195.75,60L224,85.8V56a8,8,0,1,1,16,0Z"] },
|
|
41
|
+
scribble: { icon: [256, 256, [], '', "M205.67,189.66a14.61,14.61,0,0,0,0,20.68,8,8,0,0,1-11.32,11.32,30.64,30.64,0,0,1,0-43.32l9.38-9.37A14.63,14.63,0,0,0,183,148.28L116.28,215A30.63,30.63,0,0,1,73,171.72L171.72,73A14.63,14.63,0,0,0,151,52.28L84.28,119A30.63,30.63,0,0,1,41,75.72L82.34,34.34A8,8,0,0,1,93.65,45.66L52.27,87A14.63,14.63,0,0,0,73,107.72L139.72,41A30.63,30.63,0,0,1,183,84.28L84.28,183A14.63,14.63,0,0,0,105,203.72L171.72,137A30.63,30.63,0,0,1,215,180.28Z"] },
|
|
42
|
+
shapes: { icon: [256, 256, [], '', "M71.59,61.47a8,8,0,0,0-15.18,0l-40,120A8,8,0,0,0,24,192h80a8,8,0,0,0,7.59-10.53ZM35.1,176,64,89.3,92.9,176ZM208,76a52,52,0,1,0-52,52A52.06,52.06,0,0,0,208,76Zm-88,0a36,36,0,1,1,36,36A36,36,0,0,1,120,76Zm104,68H136a8,8,0,0,0-8,8v56a8,8,0,0,0,8,8h88a8,8,0,0,0,8-8V152A8,8,0,0,0,224,144Zm-8,56H144V160h72Z"] },
|
|
43
|
+
slash: { icon: [256, 256, [], '', "M214.64,41.36a32,32,0,0,0-50.2,38.89L80.25,164.44a32.06,32.06,0,0,0-38.89,4.94h0a32,32,0,1,0,50.2,6.37l84.19-84.19a32,32,0,0,0,38.89-50.2Zm-139.33,162a16,16,0,0,1-22.64-22.64h0a16,16,0,0,1,22.63,0h0A16,16,0,0,1,75.31,203.33Zm128-128a16,16,0,1,1,0-22.63A16,16,0,0,1,203.33,75.3Z"] },
|
|
44
|
+
square: { icon: [256, 256, [], '', "M208,32H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32Zm0,176H48V48H208V208Z"] },
|
|
45
|
+
stop: { icon: [256, 256, [], '', "M200,40H56A16,16,0,0,0,40,56V200a16,16,0,0,0,16,16H200a16,16,0,0,0,16-16V56A16,16,0,0,0,200,40Zm0,160H56V56H200V200Z"] },
|
|
46
|
+
stopwatch: { icon: [256, 256, [], '', "M128,40a96,96,0,1,0,96,96A96.11,96.11,0,0,0,128,40Zm0,176a80,80,0,1,1,80-80A80.09,80.09,0,0,1,128,216ZM173.66,90.34a8,8,0,0,1,0,11.32l-40,40a8,8,0,0,1-11.32-11.32l40-40A8,8,0,0,1,173.66,90.34ZM96,16a8,8,0,0,1,8-8h48a8,8,0,0,1,0,16H104A8,8,0,0,1,96,16Z"] },
|
|
47
|
+
subtract: { icon: [256, 256, [], '', "M174.63,81.35a80,80,0,1,0-93.28,93.28,80,80,0,1,0,93.28-93.28ZM224,160c0,1.52-.07,3-.18,4.51l-50-50A80.14,80.14,0,0,0,176,98,63.81,63.81,0,0,1,224,160Zm-77.4-2.09,52.61,52.62A64,64,0,0,1,183,219.7l-51.86-51.86A80.5,80.5,0,0,0,146.6,157.91Zm11.31-11.31a80.5,80.5,0,0,0,9.93-15.44L219.7,183a64,64,0,0,1-9.17,16.19ZM32,96a64,64,0,1,1,64,64A64.07,64.07,0,0,1,32,96ZM98,176a80.14,80.14,0,0,0,16.5-2.13l50,50c-1.49.11-3,.18-4.51.18A63.81,63.81,0,0,1,98,176Z"] },
|
|
48
|
+
times: { icon: [256, 256, [], '', "M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"] },
|
|
49
|
+
triangle: { icon: [256, 256, [], '', "M236.8,188.09,149.35,36.22a24.76,24.76,0,0,0-42.7,0L19.2,188.09a23.51,23.51,0,0,0,0,23.72A24.34,24.34,0,0,0,40.55,224h174.9a24.34,24.34,0,0,0,21.33-12.19A23.51,23.51,0,0,0,236.8,188.09ZM222.93,203.8a8.5,8.5,0,0,1-7.48,4.2H40.55a8.5,8.5,0,0,1-7.48-4.2,7.59,7.59,0,0,1,0-7.72L120.52,44.21a8.75,8.75,0,0,1,15,0l87.45,151.87A7.59,7.59,0,0,1,222.93,203.8Z"] },
|
|
50
|
+
"toggle-off": { icon: [256, 256, [], '', "M176,56H80a72,72,0,0,0,0,144h96a72,72,0,0,0,0-144Zm0,128H80A56,56,0,0,1,80,72h96a56,56,0,0,1,0,112ZM80,88a40,40,0,1,0,40,40A40,40,0,0,0,80,88Zm0,64a24,24,0,1,1,24-24A24,24,0,0,1,80,152Z"] },
|
|
51
|
+
"toggle-on": { icon: [256, 256, [], '', "M176,56H80a72,72,0,0,0,0,144h96a72,72,0,0,0,0-144Zm0,128H80A56,56,0,0,1,80,72h96a56,56,0,0,1,0,112Zm0-96a40,40,0,1,0,40,40A40,40,0,0,0,176,88Zm0,64a24,24,0,1,1,24-24A24,24,0,0,1,176,152Z"] },
|
|
52
|
+
trash: { icon: [256, 256, [], '', "M216,48H176V40a24,24,0,0,0-24-24H104A24,24,0,0,0,80,40v8H40a8,8,0,0,0,0,16h8V208a16,16,0,0,0,16,16H192a16,16,0,0,0,16-16V64h8a8,8,0,0,0,0-16ZM96,40a8,8,0,0,1,8-8h48a8,8,0,0,1,8,8v8H96Zm96,168H64V64H192ZM112,104v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm48,0v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Z"] },
|
|
53
|
+
undo: { icon: [256, 256, [], '', "M232,144a64.07,64.07,0,0,1-64,64H80a8,8,0,0,1,0-16h88a48,48,0,0,0,0-96H51.31l34.35,34.34a8,8,0,0,1-11.32,11.32l-48-48a8,8,0,0,1,0-11.32l48-48A8,8,0,0,1,85.66,45.66L51.31,80H168A64.07,64.07,0,0,1,232,144Z"] },
|
|
54
|
+
"zoom-in": { icon: [256, 256, [], '', "M152,112a8,8,0,0,1-8,8H120v24a8,8,0,0,1-16,0V120H80a8,8,0,0,1,0-16h24V80a8,8,0,0,1,16,0v24h24A8,8,0,0,1,152,112Zm77.66,117.66a8,8,0,0,1-11.32,0l-50.06-50.07a88.11,88.11,0,1,1,11.31-11.31l50.07,50.06A8,8,0,0,1,229.66,229.66ZM112,184a72,72,0,1,0-72-72A72.08,72.08,0,0,0,112,184Z"] },
|
|
55
|
+
"zoom-out": { icon: [256, 256, [], '', "M152,112a8,8,0,0,1-8,8H80a8,8,0,0,1,0-16h64A8,8,0,0,1,152,112Zm77.66,117.66a8,8,0,0,1-11.32,0l-50.06-50.07a88.11,88.11,0,1,1,11.31-11.31l50.07,50.06A8,8,0,0,1,229.66,229.66ZM112,184a72,72,0,1,0-72-72A72.08,72.08,0,0,0,112,184Z"] },
|
|
56
|
+
};
|
|
@@ -20,17 +20,12 @@ import {
|
|
|
20
20
|
} from '@dnd-kit/sortable';
|
|
21
21
|
import { CSS } from '@dnd-kit/utilities';
|
|
22
22
|
|
|
23
|
-
// Hold
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
// gesture, so a press that was really the start of a scroll stays a scroll.
|
|
30
|
-
// A finger waits longer than a mouse -- a finger resting on a surface is
|
|
31
|
-
// ordinary, a held mouse button is deliberate.
|
|
32
|
-
const MOUSE_ACTIVATION = { delay: 200, tolerance: 6 };
|
|
33
|
-
const TOUCH_ACTIVATION = { delay: 380, tolerance: 8 };
|
|
23
|
+
// Hold / move to reorder via the grip only -- the rest of the title row must
|
|
24
|
+
// stay free for scrolling (especially on phones) and for the disclosure /
|
|
25
|
+
// enable controls. Arming on distance rather than a long press: the grip has
|
|
26
|
+
// `touch-action: none`, so there is no scroll gesture to yield to there.
|
|
27
|
+
const MOUSE_ACTIVATION = { distance: 4 };
|
|
28
|
+
const TOUCH_ACTIVATION = { distance: 8 };
|
|
34
29
|
|
|
35
30
|
export function PanelSortContext({ names, onReorder, children }) {
|
|
36
31
|
const sensors = useSensors(
|
|
@@ -61,9 +56,7 @@ export function PanelSortContext({ names, onReorder, children }) {
|
|
|
61
56
|
);
|
|
62
57
|
}
|
|
63
58
|
|
|
64
|
-
// One sortable row. Returns the props for the row element and the handle
|
|
65
|
-
// the caller decides what the handle looks like -- here it is the grip in the
|
|
66
|
-
// panel header, which is several components away.
|
|
59
|
+
// One sortable row. Returns the props for the row element and the grip handle.
|
|
67
60
|
export function usePanelSortable(id) {
|
|
68
61
|
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
|
|
69
62
|
id,
|
|
@@ -2,8 +2,9 @@ import { isBehaviorEnabled } from '../scene';
|
|
|
2
2
|
// The physics system: one matter-js engine per scene runtime. Registered as a
|
|
3
3
|
// runtime system (see engine/scene.js `registerSystem`), it runs once per frame
|
|
4
4
|
// in `afterBehaviors` -- after behaviors have expressed intent (velocities,
|
|
5
|
-
// forces) -- to reconcile bodies,
|
|
6
|
-
// write results back into
|
|
5
|
+
// forces) -- to reconcile bodies, push any Layout writes onto the matching
|
|
6
|
+
// bodies, step the simulation on a fixed timestep, and write results back into
|
|
7
|
+
// each dynamic actor's Layout.
|
|
7
8
|
//
|
|
8
9
|
// The matter engine is created lazily on first step, so draw-only editor
|
|
9
10
|
// previews (which never call update) pay nothing.
|
|
@@ -13,6 +14,7 @@ import { getColliderRect } from '../collider';
|
|
|
13
14
|
import { buildJointConstraints, jointSignature, patchJoint } from './joints';
|
|
14
15
|
import {
|
|
15
16
|
DEFAULT_GRAVITY,
|
|
17
|
+
DEG_TO_RAD,
|
|
16
18
|
FIXED_STEP_MS,
|
|
17
19
|
FIXED_STEP_S,
|
|
18
20
|
MAX_STEPS_PER_FRAME,
|
|
@@ -31,9 +33,9 @@ import {
|
|
|
31
33
|
export class PhysicsSystem {
|
|
32
34
|
constructor() {
|
|
33
35
|
this.engine = null;
|
|
34
|
-
this.bodies = new Map(); // actorId -> { body, sig, offset: {dx, dy} }
|
|
36
|
+
this.bodies = new Map(); // actorId -> { body, sig, offset: {dx, dy}, last }
|
|
35
37
|
this.joints = new Map(); // `${ownerId}#${listIndex}` -> { constraints, bodyA, bodyB, sig }
|
|
36
|
-
this.intents = new Map(); // actorId -> { velocity?, impulse?, force? }
|
|
38
|
+
this.intents = new Map(); // actorId -> { velocity?, impulse?, force?, angularVelocity? }
|
|
37
39
|
this.grabs = new Map(); // actorId -> { constraint, localPoint }
|
|
38
40
|
this.gravity = { ...DEFAULT_GRAVITY };
|
|
39
41
|
this.acc = 0;
|
|
@@ -93,7 +95,7 @@ export class PhysicsSystem {
|
|
|
93
95
|
this.reconcile(scene);
|
|
94
96
|
this.reconcileJoints(scene);
|
|
95
97
|
this.applyIntents();
|
|
96
|
-
this.
|
|
98
|
+
this.syncBodiesFromLayout(scene);
|
|
97
99
|
this.step(dt);
|
|
98
100
|
this.writeBack(scene);
|
|
99
101
|
this.detectNonDynamicContacts();
|
|
@@ -186,7 +188,10 @@ export class PhysicsSystem {
|
|
|
186
188
|
const center = rectCenter(rect);
|
|
187
189
|
const layout = actor.components.Layout;
|
|
188
190
|
const offset = { dx: center.x - layout.x, dy: center.y - layout.y };
|
|
189
|
-
|
|
191
|
+
// Cache what physics last wrote so a later Layout write can be detected
|
|
192
|
+
// with !== (raw values: an omitted rotation stays undefined).
|
|
193
|
+
const last = { x: layout.x, y: layout.y, rotation: layout.rotation };
|
|
194
|
+
this.bodies.set(actor.id, { body, sig: bodySignature(actor, rect), offset, last });
|
|
190
195
|
Matter.Composite.add(this.engine.world, body);
|
|
191
196
|
}
|
|
192
197
|
|
|
@@ -223,19 +228,39 @@ export class PhysicsSystem {
|
|
|
223
228
|
});
|
|
224
229
|
}
|
|
225
230
|
if (intent.force) Matter.Body.applyForce(body, body.position, intent.force);
|
|
231
|
+
if (intent.angularVelocity != null) {
|
|
232
|
+
Matter.Body.setAngularVelocity(body, intent.angularVelocity * DEG_TO_RAD);
|
|
233
|
+
}
|
|
226
234
|
}
|
|
227
235
|
this.intents.clear();
|
|
228
236
|
}
|
|
229
237
|
|
|
230
|
-
//
|
|
231
|
-
// behavior moving a platform
|
|
232
|
-
|
|
238
|
+
// Push Layout writes onto bodies before the step. Static/kinematic always
|
|
239
|
+
// follow Layout (editor edits, or a behavior moving a platform). Dynamic
|
|
240
|
+
// bodies only sync fields that differ from what writeBack last wrote — an
|
|
241
|
+
// untouched field must not get a float-roundtrip micro-delta.
|
|
242
|
+
syncBodiesFromLayout(scene) {
|
|
233
243
|
for (const [id, entry] of this.bodies) {
|
|
234
|
-
if (!entry.body.isStatic) continue;
|
|
235
244
|
const actor = scene.getActor(id);
|
|
236
245
|
if (!actor) continue;
|
|
237
246
|
const layout = actor.components.Layout;
|
|
238
|
-
|
|
247
|
+
if (entry.body.isStatic) {
|
|
248
|
+
syncBodyToPoint(entry.body, { x: layout.x + entry.offset.dx, y: layout.y + entry.offset.dy }, layout.rotation);
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
const { last } = entry;
|
|
252
|
+
if (layout.x !== last.x || layout.y !== last.y) {
|
|
253
|
+
Matter.Body.setPosition(entry.body, {
|
|
254
|
+
x: layout.x + entry.offset.dx,
|
|
255
|
+
y: layout.y + entry.offset.dy,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
if (layout.rotation !== last.rotation) {
|
|
259
|
+
Matter.Body.setAngle(entry.body, (layout.rotation ?? 0) * DEG_TO_RAD);
|
|
260
|
+
}
|
|
261
|
+
last.x = layout.x;
|
|
262
|
+
last.y = layout.y;
|
|
263
|
+
last.rotation = layout.rotation;
|
|
239
264
|
}
|
|
240
265
|
}
|
|
241
266
|
|
|
@@ -263,9 +288,18 @@ export class PhysicsSystem {
|
|
|
263
288
|
layout.x = entry.body.position.x - entry.offset.dx;
|
|
264
289
|
layout.y = entry.body.position.y - entry.offset.dy;
|
|
265
290
|
layout.rotation = entry.body.angle * RAD_TO_DEG;
|
|
291
|
+
entry.last.x = layout.x;
|
|
292
|
+
entry.last.y = layout.y;
|
|
293
|
+
entry.last.rotation = layout.rotation;
|
|
266
294
|
}
|
|
267
295
|
}
|
|
268
296
|
|
|
297
|
+
layoutOf(actorOrId) {
|
|
298
|
+
const actor =
|
|
299
|
+
typeof actorOrId === 'string' ? this.lastScene?.getActor(actorOrId) : actorOrId;
|
|
300
|
+
return actor?.components?.Layout ?? null;
|
|
301
|
+
}
|
|
302
|
+
|
|
269
303
|
// matter-js only generates contacts when at least one body is dynamic, so it
|
|
270
304
|
// never reports overlaps between two non-dynamic bodies (static-static, or
|
|
271
305
|
// any pair involving an emulated-kinematic body, which is matter-static).
|
|
@@ -449,6 +483,27 @@ export class PhysicsSystem {
|
|
|
449
483
|
const body = this.bodyOf(actor);
|
|
450
484
|
return body ? { x: body.velocity.x, y: body.velocity.y } : { x: 0, y: 0 };
|
|
451
485
|
},
|
|
486
|
+
// Degrees per fixed step (matches RigidBody.angularVelocity). Set to 0
|
|
487
|
+
// to stop a spin before driving rotation by hand.
|
|
488
|
+
setAngularVelocity: (actor, degPerStep) =>
|
|
489
|
+
this.queue(actor, 'angularVelocity', degPerStep),
|
|
490
|
+
getAngularVelocity: (actor) => {
|
|
491
|
+
const body = this.bodyOf(actor);
|
|
492
|
+
return body ? body.angularVelocity * RAD_TO_DEG : 0;
|
|
493
|
+
},
|
|
494
|
+
// Thin sugar over Layout writes — teleport the actor (velocity kept).
|
|
495
|
+
// Works for dynamic, kinematic, static, and body-less actors alike.
|
|
496
|
+
setRotation: (actor, deg) => {
|
|
497
|
+
const layout = this.layoutOf(actor);
|
|
498
|
+
if (layout) layout.rotation = deg;
|
|
499
|
+
},
|
|
500
|
+
// Layout top-left convention (not body center).
|
|
501
|
+
setPosition: (actor, { x, y }) => {
|
|
502
|
+
const layout = this.layoutOf(actor);
|
|
503
|
+
if (!layout) return;
|
|
504
|
+
layout.x = x;
|
|
505
|
+
layout.y = y;
|
|
506
|
+
},
|
|
452
507
|
// True while two actors are touching (updated by collision events).
|
|
453
508
|
isColliding: (a, b) => {
|
|
454
509
|
const aId = typeof a === 'string' ? a : a?.id;
|
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
// thin wrappers: read input + runtime state, call these, push the result
|
|
5
5
|
// through scene.physics. (Controls are touch/pointer-first; keyboard, when
|
|
6
6
|
// added, should only DUPLICATE an on-screen control, never be the only input.)
|
|
7
|
+
//
|
|
8
|
+
// AnalogStick force mode: stickDrive (held) and stickBrake (idle) return
|
|
9
|
+
// velocity deltas applied via applyImpulse — mass-independent, composable,
|
|
10
|
+
// and restricted to the stick's driven axes so gravity on an undriven axis
|
|
11
|
+
// is never clamped or braked.
|
|
7
12
|
|
|
8
13
|
// Authored Draggable `stiffness` (0..1, 0 = floppy .. 1 = rigid) -> the matter
|
|
9
14
|
// constraint values that hold the object. Geometric, like joints.js's rope map
|
|
@@ -68,9 +73,10 @@ export function acquirePress(scene, actorId, priorityFor) {
|
|
|
68
73
|
}
|
|
69
74
|
|
|
70
75
|
// Run `draw(ctx)` in world space, undoing the actor's Layout rotation that the
|
|
71
|
-
// runtime applies about the actor's center.
|
|
72
|
-
//
|
|
73
|
-
//
|
|
76
|
+
// runtime applies about the actor's center. Overlays anchored to world objects
|
|
77
|
+
// (Slingshot, Draggable, Joints) use this so their art stays aligned with the
|
|
78
|
+
// actor's position without rotating/sliding with it. Still moves with the
|
|
79
|
+
// camera -- for screen-fixed HUD use `drawUi` instead.
|
|
74
80
|
export function inActorWorldSpace(ctx, layout, draw) {
|
|
75
81
|
const rot = layout?.rotation ?? 0;
|
|
76
82
|
ctx.save();
|
|
@@ -103,15 +109,73 @@ export function stickVector(pointer, origin, maxRadius = 60) {
|
|
|
103
109
|
return clampLength({ x: pointer.x - origin.x, y: pointer.y - origin.y }, maxRadius);
|
|
104
110
|
}
|
|
105
111
|
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
|
|
112
|
+
// Card coords before the camera -- for screen-fixed controls reading a pointer.
|
|
113
|
+
export function screenPoint(pointer) {
|
|
114
|
+
return { x: pointer.screenX, y: pointer.screenY };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Keep only the axes the stick is allowed to drive. An undriven axis (gravity
|
|
118
|
+
// in a platformer) must never be clamped or braked by the stick.
|
|
119
|
+
function drivenAxes(v, axes) {
|
|
120
|
+
return {
|
|
121
|
+
x: axes === 'vertical' ? 0 : v.x,
|
|
122
|
+
y: axes === 'horizontal' ? 0 : v.y,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Smallest signed angle from `from` to `to`, wrapped into [−π, π].
|
|
127
|
+
function angleDelta(from, to) {
|
|
128
|
+
let d = Math.atan2(to.y, to.x) - Math.atan2(from.y, from.x);
|
|
129
|
+
if (d > Math.PI) d -= 2 * Math.PI;
|
|
130
|
+
if (d < -Math.PI) d += 2 * Math.PI;
|
|
131
|
+
return d;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Velocity delta while the stick is held: accelerate toward deflection × speed
|
|
135
|
+
// with OG turnFriction boost on reversals, then clamp the driven axes to `speed`.
|
|
136
|
+
// Returns an impulse (add to velocity); never touches an undriven axis.
|
|
137
|
+
export function stickDrive(velocity, deflection, props = {}, dt) {
|
|
109
138
|
const speed = props.speed ?? 6;
|
|
110
|
-
const
|
|
139
|
+
const rampTime = props.rampTime ?? 0.2;
|
|
140
|
+
const turnBoost = props.turnBoost ?? 3;
|
|
141
|
+
const axes = props.axes ?? 'both';
|
|
142
|
+
const vDriven = drivenAxes(velocity, axes);
|
|
143
|
+
|
|
144
|
+
let boost = 1;
|
|
145
|
+
if (turnBoost > 0 && length(velocity) > 0 && length(deflection) > 0) {
|
|
146
|
+
boost = 1 + turnBoost * (Math.abs(angleDelta(velocity, deflection)) / Math.PI);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
let delta;
|
|
150
|
+
if (rampTime <= 0) {
|
|
151
|
+
// Instant: one-frame snap toward the capped target on the driven axes.
|
|
152
|
+
const target = drivenAxes(
|
|
153
|
+
{ x: deflection.x * speed, y: deflection.y * speed },
|
|
154
|
+
axes,
|
|
155
|
+
);
|
|
156
|
+
delta = { x: target.x - vDriven.x, y: target.y - vDriven.y };
|
|
157
|
+
} else {
|
|
158
|
+
const accel = speed / rampTime;
|
|
159
|
+
delta = drivenAxes(
|
|
160
|
+
{ x: deflection.x * accel * boost * dt, y: deflection.y * accel * boost * dt },
|
|
161
|
+
axes,
|
|
162
|
+
);
|
|
163
|
+
const capped = clampLength({ x: vDriven.x + delta.x, y: vDriven.y + delta.y }, speed);
|
|
164
|
+
delta = { x: capped.x - vDriven.x, y: capped.y - vDriven.y };
|
|
165
|
+
}
|
|
166
|
+
return delta;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Velocity delta while the stick is idle: Coulomb brake on the driven axes only.
|
|
170
|
+
// `slowDown` is speed units lost per second (px/step per second). 0 = coast.
|
|
171
|
+
export function stickBrake(velocity, props = {}, dt) {
|
|
172
|
+
const slowDown = props.slowDown ?? 20;
|
|
173
|
+
if (slowDown <= 0) return { x: 0, y: 0 };
|
|
111
174
|
const axes = props.axes ?? 'both';
|
|
112
|
-
const
|
|
113
|
-
const
|
|
114
|
-
if (
|
|
115
|
-
|
|
116
|
-
|
|
175
|
+
const vDriven = drivenAxes(velocity, axes);
|
|
176
|
+
const len = length(vDriven);
|
|
177
|
+
if (len === 0) return { x: 0, y: 0 };
|
|
178
|
+
const reduce = Math.min(len, slowDown * dt);
|
|
179
|
+
const s = -reduce / len;
|
|
180
|
+
return { x: vDriven.x * s, y: vDriven.y * s };
|
|
117
181
|
}
|
|
@@ -60,15 +60,16 @@ export class SceneRuntime {
|
|
|
60
60
|
// an in-progress drag. `pointer` stays the primary (first-down) pointer for
|
|
61
61
|
// single-touch behaviors and for decks reading the documented API.
|
|
62
62
|
this.pointers = new Map();
|
|
63
|
-
this.pointer = { x: 0, y: 0, down: false };
|
|
63
|
+
this.pointer = { x: 0, y: 0, screenX: 0, screenY: 0, down: false };
|
|
64
64
|
this.data = { actors: [] };
|
|
65
65
|
this.actors = new Map();
|
|
66
66
|
this.camera = undefined;
|
|
67
67
|
this.status = undefined;
|
|
68
68
|
// The deck's font as a CSS font-family value, always usable: the face
|
|
69
69
|
// picked in the Style editor, or a plain sans stack when there is none.
|
|
70
|
-
// For `draw` hooks -- `ctx.font = `20px ${scene.font}`` -- since
|
|
71
|
-
// takes a family name, not a class.
|
|
70
|
+
// For `draw` / `drawUi` hooks -- `ctx.font = `20px ${scene.font}`` -- since
|
|
71
|
+
// canvas takes a family name, not a class. Prefer `drawUi` for HUD text;
|
|
72
|
+
// the deprecated React `ui` overlay still inherits this face via CSS.
|
|
72
73
|
this.font = deckFontFamily;
|
|
73
74
|
// Registered systems run once per frame after all behavior `update`s (see
|
|
74
75
|
// `update`). A system is a plain object with an optional
|
|
@@ -256,22 +257,36 @@ export class SceneRuntime {
|
|
|
256
257
|
const point = screenToCard(canvas, clientX, clientY);
|
|
257
258
|
const x = point.x + (this.camera?.x ?? 0);
|
|
258
259
|
const y = point.y + (this.camera?.y ?? 0);
|
|
260
|
+
const screenX = point.x;
|
|
261
|
+
const screenY = point.y;
|
|
259
262
|
let p = this.pointers.get(pointerId);
|
|
260
263
|
if (!p) {
|
|
261
264
|
// Only a press creates a pointer. A move with no press is a mouse hover,
|
|
262
265
|
// and a stray event after release must not resurrect a finished contact.
|
|
263
|
-
if (down !== true) return this.syncPrimaryPointer(x, y);
|
|
264
|
-
p = {
|
|
266
|
+
if (down !== true) return this.syncPrimaryPointer({ x, y, screenX, screenY });
|
|
267
|
+
p = {
|
|
268
|
+
id: pointerId,
|
|
269
|
+
x,
|
|
270
|
+
y,
|
|
271
|
+
screenX,
|
|
272
|
+
screenY,
|
|
273
|
+
down: false,
|
|
274
|
+
justPressed: false,
|
|
275
|
+
claimedBy: null,
|
|
276
|
+
claimPriority: 0,
|
|
277
|
+
};
|
|
265
278
|
this.pointers.set(pointerId, p);
|
|
266
279
|
}
|
|
267
280
|
p.x = x;
|
|
268
281
|
p.y = y;
|
|
282
|
+
p.screenX = screenX;
|
|
283
|
+
p.screenY = screenY;
|
|
269
284
|
// The press edge is per-pointer, so a finger landing while another is
|
|
270
285
|
// already held still registers as a new press (a shared `down` flag would
|
|
271
286
|
// show no rising edge and the second press would be invisible).
|
|
272
287
|
if (down === true && !p.down) p.justPressed = true;
|
|
273
288
|
if (down !== undefined) p.down = down;
|
|
274
|
-
this.syncPrimaryPointer(x, y);
|
|
289
|
+
this.syncPrimaryPointer({ x, y, screenX, screenY });
|
|
275
290
|
}
|
|
276
291
|
|
|
277
292
|
// Claim a pointer for one gesture, so two controls can't both act on the same
|
|
@@ -318,16 +333,23 @@ export class SceneRuntime {
|
|
|
318
333
|
// `pointer` mirrors the primary -- the oldest pointer still held (Map keeps
|
|
319
334
|
// insertion order) -- so single-touch behaviors and decks reading the
|
|
320
335
|
// documented `scene.pointer` API behave exactly as before.
|
|
321
|
-
|
|
336
|
+
// `fallback` is `{ x, y, screenX, screenY }` for the hover path (no press yet).
|
|
337
|
+
syncPrimaryPointer(fallback) {
|
|
322
338
|
for (const p of this.pointers.values()) {
|
|
323
339
|
if (!p.down) continue;
|
|
324
340
|
this.pointer.x = p.x;
|
|
325
341
|
this.pointer.y = p.y;
|
|
342
|
+
this.pointer.screenX = p.screenX;
|
|
343
|
+
this.pointer.screenY = p.screenY;
|
|
326
344
|
this.pointer.down = true;
|
|
327
345
|
return;
|
|
328
346
|
}
|
|
329
|
-
if (
|
|
330
|
-
|
|
347
|
+
if (fallback) {
|
|
348
|
+
this.pointer.x = fallback.x;
|
|
349
|
+
this.pointer.y = fallback.y;
|
|
350
|
+
this.pointer.screenX = fallback.screenX;
|
|
351
|
+
this.pointer.screenY = fallback.screenY;
|
|
352
|
+
}
|
|
331
353
|
this.pointer.down = false;
|
|
332
354
|
}
|
|
333
355
|
|
|
@@ -454,6 +476,22 @@ export class SceneRuntime {
|
|
|
454
476
|
if (options.marquee) drawMarquee(ctx, options.marquee);
|
|
455
477
|
if (options.showCropOutline) drawCropOutline(ctx);
|
|
456
478
|
ctx.restore();
|
|
479
|
+
|
|
480
|
+
// Screen-space pass after the camera block so HUD / on-screen controls
|
|
481
|
+
// composite above the world and stay put while the camera scrolls.
|
|
482
|
+
this.#drawUiPass(ctx, viewport, options);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Screen-space pass: card units, no camera, no actor rotation. Preferred
|
|
486
|
+
// path for HUD and on-screen controls that must stay put while the world
|
|
487
|
+
// scrolls (the React `ui()` hook is deprecated).
|
|
488
|
+
#drawUiPass(ctx, viewport, options) {
|
|
489
|
+
ctx.save();
|
|
490
|
+
ctx.translate(viewport.originX, viewport.originY);
|
|
491
|
+
for (const actor of this.getActors()) {
|
|
492
|
+
this.forEachBehavior(actor, (instance) => instance.drawUi?.(actor, this, ctx, options));
|
|
493
|
+
}
|
|
494
|
+
ctx.restore();
|
|
457
495
|
}
|
|
458
496
|
|
|
459
497
|
actorAt(x, y) {
|
|
@@ -1,58 +1,6 @@
|
|
|
1
1
|
import React, { useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
2
2
|
import { createPortal } from 'react-dom';
|
|
3
|
-
import {
|
|
4
|
-
faArrowsAlt,
|
|
5
|
-
faArrowsAltH,
|
|
6
|
-
faArrowsAltV,
|
|
7
|
-
faBars,
|
|
8
|
-
faBezierCurve,
|
|
9
|
-
faChevronDown,
|
|
10
|
-
faChevronLeft,
|
|
11
|
-
faChevronRight,
|
|
12
|
-
faChevronUp,
|
|
13
|
-
faCircle,
|
|
14
|
-
faClone,
|
|
15
|
-
faCode,
|
|
16
|
-
faCodeBranch,
|
|
17
|
-
faDotCircle,
|
|
18
|
-
faDrawPolygon,
|
|
19
|
-
faEraser,
|
|
20
|
-
faExpand,
|
|
21
|
-
faExternalLinkAlt,
|
|
22
|
-
faEyeDropper,
|
|
23
|
-
faFile,
|
|
24
|
-
faFilm,
|
|
25
|
-
faFillDrip,
|
|
26
|
-
faGlobe,
|
|
27
|
-
faGripVertical,
|
|
28
|
-
faToggleOff,
|
|
29
|
-
faToggleOn,
|
|
30
|
-
faImage,
|
|
31
|
-
faLayerGroup,
|
|
32
|
-
faLocationArrow,
|
|
33
|
-
faObjectGroup,
|
|
34
|
-
faPaintBrush,
|
|
35
|
-
faPalette,
|
|
36
|
-
faPencilAlt,
|
|
37
|
-
faPenNib,
|
|
38
|
-
faPlay,
|
|
39
|
-
faPlus,
|
|
40
|
-
faRedo,
|
|
41
|
-
faSearchMinus,
|
|
42
|
-
faSearchPlus,
|
|
43
|
-
faShapes,
|
|
44
|
-
faSlash,
|
|
45
|
-
faVectorSquare,
|
|
46
|
-
faSquare,
|
|
47
|
-
faStamp,
|
|
48
|
-
faStop,
|
|
49
|
-
faSyncAlt,
|
|
50
|
-
faTh,
|
|
51
|
-
faTimes,
|
|
52
|
-
faTrash,
|
|
53
|
-
faUndo,
|
|
54
|
-
faVideo,
|
|
55
|
-
} from '@fortawesome/free-solid-svg-icons';
|
|
3
|
+
import { icons } from './icons';
|
|
56
4
|
import styles from './ui.module.css';
|
|
57
5
|
export { styles };
|
|
58
6
|
export const theme = {
|
|
@@ -219,72 +167,8 @@ export function IconButton({ icon, label, active = false, variant = '', ...props
|
|
|
219
167
|
</Button>
|
|
220
168
|
);
|
|
221
169
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
'bezier-curve': faBezierCurve,
|
|
225
|
-
camera: faVideo,
|
|
226
|
-
'chevron-down': faChevronDown,
|
|
227
|
-
'chevron-left': faChevronLeft,
|
|
228
|
-
'chevron-right': faChevronRight,
|
|
229
|
-
'chevron-up': faChevronUp,
|
|
230
|
-
circle: faCircle,
|
|
231
|
-
clone: faClone,
|
|
232
|
-
code: faCode,
|
|
233
|
-
// FA5 has no faCodeFork (that's the FA6 name); faCodeBranch is the fork glyph.
|
|
234
|
-
//
|
|
235
|
-
// Reserved for forking a FILE -- taking this deck's own version of one an
|
|
236
|
-
// import owns -- which is what it means in the shell's file tree and editor
|
|
237
|
-
// banner too. Nothing in this kit draws it since the actor action became
|
|
238
|
-
// `clone`; kept because a deck or a kit pinned to an older physics-2d may
|
|
239
|
-
// still ask for it by name, and an unused entry costs less than a missing
|
|
240
|
-
// glyph on somebody else's screen.
|
|
241
|
-
'code-fork': faCodeBranch,
|
|
242
|
-
'dot-circle': faDotCircle,
|
|
243
|
-
'draw-polygon': faDrawPolygon,
|
|
244
|
-
eraser: faEraser,
|
|
245
|
-
expand: faExpand,
|
|
246
|
-
external: faExternalLinkAlt,
|
|
247
|
-
eyedropper: faEyeDropper,
|
|
248
|
-
fill: faFillDrip,
|
|
249
|
-
'flip-h': faArrowsAltH,
|
|
250
|
-
'flip-v': faArrowsAltV,
|
|
251
|
-
file: faFile,
|
|
252
|
-
film: faFilm,
|
|
253
|
-
globe: faGlobe,
|
|
254
|
-
grip: faGripVertical,
|
|
255
|
-
'toggle-off': faToggleOff,
|
|
256
|
-
'toggle-on': faToggleOn,
|
|
257
|
-
grid: faTh,
|
|
258
|
-
image: faImage,
|
|
259
|
-
'layer-group': faLayerGroup,
|
|
260
|
-
// FA's location-arrow points up-right; flip it for a path-select cursor feel.
|
|
261
|
-
'location-arrow': { ...faLocationArrow, flipX: true },
|
|
262
|
-
marquee: faVectorSquare,
|
|
263
|
-
move: faArrowsAlt,
|
|
264
|
-
'object-group': faObjectGroup,
|
|
265
|
-
paintbrush: faPaintBrush,
|
|
266
|
-
palette: faPalette,
|
|
267
|
-
pencil: faPencilAlt,
|
|
268
|
-
'pen-nib': faPenNib,
|
|
269
|
-
play: faPlay,
|
|
270
|
-
plus: faPlus,
|
|
271
|
-
redo: faRedo,
|
|
272
|
-
rotate: faSyncAlt,
|
|
273
|
-
'zoom-in': faSearchPlus,
|
|
274
|
-
'zoom-out': faSearchMinus,
|
|
275
|
-
fit: faExpand,
|
|
276
|
-
shapes: faShapes,
|
|
277
|
-
slash: faSlash,
|
|
278
|
-
square: faSquare,
|
|
279
|
-
stamp: faStamp,
|
|
280
|
-
stop: faStop,
|
|
281
|
-
times: faTimes,
|
|
282
|
-
// Hand-rolled equilateral-ish triangle glyph (FA free-solid has no plain
|
|
283
|
-
// triangle); shaped to match the filled-glyph look of the imported icons.
|
|
284
|
-
triangle: { icon: [512, 512, [], '', 'M256 64 L496 448 L16 448 Z'] },
|
|
285
|
-
trash: faTrash,
|
|
286
|
-
undo: faUndo,
|
|
287
|
-
};
|
|
170
|
+
// `code-fork` is generated and unused in this kit (the actor action is `clone`);
|
|
171
|
+
// kept so a deck or older kit still asking for it by name gets a glyph.
|
|
288
172
|
export function Icon({ name }) {
|
|
289
173
|
const def = icons[name];
|
|
290
174
|
if (!def) return null;
|
|
@@ -383,14 +267,18 @@ export function Panel({ title, action, children, overridden = false }) {
|
|
|
383
267
|
<section className={cx(styles.panel, behavior?.dragging && styles.panelDragging)}>
|
|
384
268
|
{title ? (
|
|
385
269
|
<div
|
|
386
|
-
className={cx(styles.panelHeader, collapsed && styles.panelHeaderCollapsed)}
|
|
387
|
-
{...(behavior?.handleProps ?? {})}>
|
|
270
|
+
className={cx(styles.panelHeader, collapsed && styles.panelHeaderCollapsed)}>
|
|
388
271
|
{collapsible && behavior.handleProps ? (
|
|
389
|
-
//
|
|
390
|
-
//
|
|
391
|
-
<
|
|
272
|
+
// Real drag handle: listeners live here so the rest of the header
|
|
273
|
+
// can scroll on touch. `touch-action: none` is on the grip only.
|
|
274
|
+
<button
|
|
275
|
+
type="button"
|
|
276
|
+
className={styles.panelGrip}
|
|
277
|
+
title="Drag to reorder"
|
|
278
|
+
aria-label={`Reorder ${title}`}
|
|
279
|
+
{...behavior.handleProps}>
|
|
392
280
|
<Icon name="grip" />
|
|
393
|
-
</
|
|
281
|
+
</button>
|
|
394
282
|
) : null}
|
|
395
283
|
{collapsible ? (
|
|
396
284
|
// The whole title row is the hit target, not just the chevron --
|