spoint 0.1.0 → 0.1.11

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 (204) hide show
  1. package/README.md +134 -209
  2. package/SKILL.md +95 -0
  3. package/apps/environment/index.js +200 -1
  4. package/apps/environment/models/decorative/.gitkeep +0 -0
  5. package/apps/environment/models/hazards/.gitkeep +0 -0
  6. package/apps/environment/models/interactive/.gitkeep +0 -0
  7. package/apps/environment/models/structures/.gitkeep +0 -0
  8. package/apps/environment/smartObjects.js +114 -0
  9. package/apps/interactable/index.js +155 -0
  10. package/apps/physics-crate/index.js +15 -9
  11. package/apps/power-crate/index.js +18 -12
  12. package/apps/tps-game/$GDUPI.vrm +0 -0
  13. package/apps/tps-game/Cleetus.vrm +0 -0
  14. package/apps/tps-game/index.js +185 -27
  15. package/apps/world/index.js +68 -22
  16. package/bin/create-app.js +337 -0
  17. package/client/ARControls.js +301 -0
  18. package/client/LoadingManager.js +117 -0
  19. package/client/MobileControls.js +1122 -0
  20. package/client/anim-lib.glb +0 -0
  21. package/client/animation.js +306 -0
  22. package/client/app.js +1341 -65
  23. package/client/camera.js +191 -33
  24. package/client/createLoadingScreen.js +69 -0
  25. package/client/editor/bridge.js +113 -0
  26. package/client/editor/css/main.css +794 -0
  27. package/client/editor/images/rotate.svg +4 -0
  28. package/client/editor/images/scale.svg +4 -0
  29. package/client/editor/images/translate.svg +4 -0
  30. package/client/editor/index.html +103 -0
  31. package/client/editor/js/Command.js +41 -0
  32. package/client/editor/js/Config.js +81 -0
  33. package/client/editor/js/Editor.js +785 -0
  34. package/client/editor/js/EditorControls.js +438 -0
  35. package/client/editor/js/History.js +321 -0
  36. package/client/editor/js/Loader.js +987 -0
  37. package/client/editor/js/LoaderUtils.js +90 -0
  38. package/client/editor/js/Menubar.Add.js +510 -0
  39. package/client/editor/js/Menubar.Edit.js +145 -0
  40. package/client/editor/js/Menubar.File.js +466 -0
  41. package/client/editor/js/Menubar.Help.js +73 -0
  42. package/client/editor/js/Menubar.Status.js +51 -0
  43. package/client/editor/js/Menubar.View.js +183 -0
  44. package/client/editor/js/Menubar.js +27 -0
  45. package/client/editor/js/Player.js +53 -0
  46. package/client/editor/js/Resizer.js +58 -0
  47. package/client/editor/js/Script.js +503 -0
  48. package/client/editor/js/Selector.js +102 -0
  49. package/client/editor/js/Sidebar.Geometry.BoxGeometry.js +121 -0
  50. package/client/editor/js/Sidebar.Geometry.BufferGeometry.js +115 -0
  51. package/client/editor/js/Sidebar.Geometry.CapsuleGeometry.js +97 -0
  52. package/client/editor/js/Sidebar.Geometry.CircleGeometry.js +97 -0
  53. package/client/editor/js/Sidebar.Geometry.CylinderGeometry.js +121 -0
  54. package/client/editor/js/Sidebar.Geometry.DodecahedronGeometry.js +73 -0
  55. package/client/editor/js/Sidebar.Geometry.ExtrudeGeometry.js +196 -0
  56. package/client/editor/js/Sidebar.Geometry.IcosahedronGeometry.js +73 -0
  57. package/client/editor/js/Sidebar.Geometry.LatheGeometry.js +98 -0
  58. package/client/editor/js/Sidebar.Geometry.Modifiers.js +73 -0
  59. package/client/editor/js/Sidebar.Geometry.OctahedronGeometry.js +74 -0
  60. package/client/editor/js/Sidebar.Geometry.PlaneGeometry.js +97 -0
  61. package/client/editor/js/Sidebar.Geometry.RingGeometry.js +121 -0
  62. package/client/editor/js/Sidebar.Geometry.ShapeGeometry.js +76 -0
  63. package/client/editor/js/Sidebar.Geometry.SphereGeometry.js +133 -0
  64. package/client/editor/js/Sidebar.Geometry.TetrahedronGeometry.js +74 -0
  65. package/client/editor/js/Sidebar.Geometry.TorusGeometry.js +109 -0
  66. package/client/editor/js/Sidebar.Geometry.TorusKnotGeometry.js +121 -0
  67. package/client/editor/js/Sidebar.Geometry.TubeGeometry.js +135 -0
  68. package/client/editor/js/Sidebar.Geometry.js +332 -0
  69. package/client/editor/js/Sidebar.Material.BooleanProperty.js +60 -0
  70. package/client/editor/js/Sidebar.Material.ColorProperty.js +87 -0
  71. package/client/editor/js/Sidebar.Material.ConstantProperty.js +62 -0
  72. package/client/editor/js/Sidebar.Material.MapProperty.js +249 -0
  73. package/client/editor/js/Sidebar.Material.NumberProperty.js +60 -0
  74. package/client/editor/js/Sidebar.Material.Program.js +73 -0
  75. package/client/editor/js/Sidebar.Material.RangeValueProperty.js +63 -0
  76. package/client/editor/js/Sidebar.Material.js +751 -0
  77. package/client/editor/js/Sidebar.Object.Animation.js +102 -0
  78. package/client/editor/js/Sidebar.Object.js +898 -0
  79. package/client/editor/js/Sidebar.Project.App.js +165 -0
  80. package/client/editor/js/Sidebar.Project.Image.js +225 -0
  81. package/client/editor/js/Sidebar.Project.Materials.js +82 -0
  82. package/client/editor/js/Sidebar.Project.Renderer.js +144 -0
  83. package/client/editor/js/Sidebar.Project.Video.js +242 -0
  84. package/client/editor/js/Sidebar.Project.js +31 -0
  85. package/client/editor/js/Sidebar.Properties.js +73 -0
  86. package/client/editor/js/Sidebar.Scene.js +585 -0
  87. package/client/editor/js/Sidebar.Script.js +129 -0
  88. package/client/editor/js/Sidebar.Settings.History.js +146 -0
  89. package/client/editor/js/Sidebar.Settings.Shortcuts.js +175 -0
  90. package/client/editor/js/Sidebar.Settings.js +60 -0
  91. package/client/editor/js/Sidebar.js +41 -0
  92. package/client/editor/js/Storage.js +98 -0
  93. package/client/editor/js/Strings.js +2028 -0
  94. package/client/editor/js/Toolbar.js +84 -0
  95. package/client/editor/js/Viewport.Controls.js +92 -0
  96. package/client/editor/js/Viewport.Info.js +136 -0
  97. package/client/editor/js/Viewport.Pathtracer.js +91 -0
  98. package/client/editor/js/Viewport.ViewHelper.js +39 -0
  99. package/client/editor/js/Viewport.XR.js +222 -0
  100. package/client/editor/js/Viewport.js +900 -0
  101. package/client/editor/js/commands/AddObjectCommand.js +68 -0
  102. package/client/editor/js/commands/AddScriptCommand.js +75 -0
  103. package/client/editor/js/commands/Commands.js +23 -0
  104. package/client/editor/js/commands/MoveObjectCommand.js +111 -0
  105. package/client/editor/js/commands/MultiCmdsCommand.js +85 -0
  106. package/client/editor/js/commands/RemoveObjectCommand.js +88 -0
  107. package/client/editor/js/commands/RemoveScriptCommand.js +81 -0
  108. package/client/editor/js/commands/SetColorCommand.js +73 -0
  109. package/client/editor/js/commands/SetGeometryCommand.js +87 -0
  110. package/client/editor/js/commands/SetGeometryValueCommand.js +70 -0
  111. package/client/editor/js/commands/SetMaterialColorCommand.js +86 -0
  112. package/client/editor/js/commands/SetMaterialCommand.js +79 -0
  113. package/client/editor/js/commands/SetMaterialMapCommand.js +143 -0
  114. package/client/editor/js/commands/SetMaterialRangeCommand.js +91 -0
  115. package/client/editor/js/commands/SetMaterialValueCommand.js +90 -0
  116. package/client/editor/js/commands/SetMaterialVectorCommand.js +79 -0
  117. package/client/editor/js/commands/SetPositionCommand.js +84 -0
  118. package/client/editor/js/commands/SetRotationCommand.js +84 -0
  119. package/client/editor/js/commands/SetScaleCommand.js +84 -0
  120. package/client/editor/js/commands/SetSceneCommand.js +103 -0
  121. package/client/editor/js/commands/SetScriptValueCommand.js +80 -0
  122. package/client/editor/js/commands/SetShadowValueCommand.js +73 -0
  123. package/client/editor/js/commands/SetUuidCommand.js +70 -0
  124. package/client/editor/js/commands/SetValueCommand.js +75 -0
  125. package/client/editor/js/libs/acorn/acorn.js +3236 -0
  126. package/client/editor/js/libs/acorn/acorn_loose.js +1299 -0
  127. package/client/editor/js/libs/acorn/walk.js +344 -0
  128. package/client/editor/js/libs/app/index.html +57 -0
  129. package/client/editor/js/libs/app.js +251 -0
  130. package/client/editor/js/libs/codemirror/addon/dialog.css +32 -0
  131. package/client/editor/js/libs/codemirror/addon/dialog.js +163 -0
  132. package/client/editor/js/libs/codemirror/addon/show-hint.css +36 -0
  133. package/client/editor/js/libs/codemirror/addon/show-hint.js +529 -0
  134. package/client/editor/js/libs/codemirror/addon/tern.css +87 -0
  135. package/client/editor/js/libs/codemirror/addon/tern.js +750 -0
  136. package/client/editor/js/libs/codemirror/codemirror.css +344 -0
  137. package/client/editor/js/libs/codemirror/codemirror.js +9849 -0
  138. package/client/editor/js/libs/codemirror/mode/glsl.js +233 -0
  139. package/client/editor/js/libs/codemirror/mode/javascript.js +959 -0
  140. package/client/editor/js/libs/codemirror/theme/monokai.css +41 -0
  141. package/client/editor/js/libs/esprima.js +6401 -0
  142. package/client/editor/js/libs/jsonlint.js +453 -0
  143. package/client/editor/js/libs/signals.min.js +14 -0
  144. package/client/editor/js/libs/tern-threejs/threejs.js +5031 -0
  145. package/client/editor/js/libs/ternjs/comment.js +87 -0
  146. package/client/editor/js/libs/ternjs/def.js +588 -0
  147. package/client/editor/js/libs/ternjs/doc_comment.js +401 -0
  148. package/client/editor/js/libs/ternjs/infer.js +1635 -0
  149. package/client/editor/js/libs/ternjs/polyfill.js +80 -0
  150. package/client/editor/js/libs/ternjs/signal.js +26 -0
  151. package/client/editor/js/libs/ternjs/tern.js +993 -0
  152. package/client/editor/js/libs/ui.js +1346 -0
  153. package/client/editor/js/libs/ui.three.js +855 -0
  154. package/client/facial-animation.js +455 -0
  155. package/client/index.html +7 -4
  156. package/client/loading.css +147 -0
  157. package/client/loading.html +25 -0
  158. package/client/style.css +251 -0
  159. package/package.json +7 -3
  160. package/server.js +9 -1
  161. package/src/apps/AppContext.js +1 -1
  162. package/src/apps/AppLoader.js +50 -37
  163. package/src/apps/AppRuntime.js +32 -8
  164. package/src/client/InputHandler.js +233 -0
  165. package/src/client/JitterBuffer.js +207 -0
  166. package/src/client/KalmanFilter.js +125 -0
  167. package/src/client/MessageHandler.js +101 -0
  168. package/src/client/PhysicsNetworkClient.js +141 -68
  169. package/src/client/ReconnectManager.js +62 -0
  170. package/src/client/SmoothInterpolation.js +127 -0
  171. package/src/client/SnapshotProcessor.js +144 -0
  172. package/src/connection/ConnectionManager.js +21 -3
  173. package/src/connection/SessionStore.js +13 -3
  174. package/src/index.client.js +4 -6
  175. package/src/netcode/EventLog.js +29 -15
  176. package/src/netcode/LagCompensator.js +25 -26
  177. package/src/netcode/NetworkState.js +4 -1
  178. package/src/netcode/PhysicsIntegration.js +20 -6
  179. package/src/netcode/PlayerManager.js +10 -2
  180. package/src/netcode/SnapshotEncoder.js +66 -19
  181. package/src/netcode/TickSystem.js +13 -4
  182. package/src/physics/World.js +66 -13
  183. package/src/protocol/msgpack.js +90 -63
  184. package/src/sdk/ReloadHandlers.js +12 -2
  185. package/src/sdk/ReloadManager.js +5 -0
  186. package/src/sdk/ServerHandlers.js +50 -11
  187. package/src/sdk/StaticHandler.js +22 -6
  188. package/src/sdk/TickHandler.js +101 -34
  189. package/src/sdk/scaffold.js +31 -0
  190. package/src/sdk/server.js +59 -33
  191. package/src/shared/movement.js +2 -1
  192. package/src/spatial/Octree.js +5 -0
  193. package/apps/interactive-door/index.js +0 -33
  194. package/apps/patrol-npc/index.js +0 -37
  195. package/src/connection/QualityMonitor.js +0 -46
  196. package/src/debug/StateInspector.js +0 -42
  197. package/src/index.js +0 -1
  198. package/src/index.server.js +0 -27
  199. package/src/protocol/Codec.js +0 -60
  200. package/src/protocol/SequenceTracker.js +0 -71
  201. package/src/sdk/ClientMessageHandler.js +0 -80
  202. package/src/sdk/client.js +0 -122
  203. package/world/kaira.glb +0 -0
  204. package/world/schwust.glb +0 -0
package/README.md CHANGED
@@ -1,250 +1,175 @@
1
- # Spawnpoint SDK - Multiplayer Physics + Netcode
1
+ # Spawnpoint
2
2
 
3
- Production-ready SDK for building multiplayer physics-based games and simulations with 128 TPS fixed timestep, hot-reload support, and display-engine agnostic architecture.
4
-
5
- ## WAVE 5: PRODUCTION READY ✓
6
-
7
- **Status: All systems verified and operational**
8
- - Server startup: ~1.8 seconds
9
- - Tick rate: 128 TPS (7.8125ms per tick)
10
- - Network snapshots: 70% compression via msgpackr
11
- - All 6 apps coexist: environment, interactive-door, patrol-npc, physics-crate, tps-game, world
12
- - TPS game: 38 validated spawn points via raycasting
13
- - Code quality: All files < 200 lines, zero duplication
14
- - Stability: Zero crashes in 30+ second test, zero memory leaks
15
- - Hot reload: Working without player disconnections
16
- - Live entity management: Spawn/remove working during gameplay
3
+ Multiplayer game server SDK. 128 TPS authoritative server, Jolt Physics WASM, WebSocket transport, hot reload.
17
4
 
18
5
  ## Quick Start
19
-
6
+
20
7
  ```bash
21
- # Install dependencies
22
8
  npm install
23
-
24
- # Start server (port 8080)
25
9
  node server.js
10
+ # http://localhost:8080
11
+ ```
26
12
 
27
- # In another terminal: Run client test
28
- node wave5-test.mjs
13
+ ## Architecture
29
14
 
30
- # Expected output:
31
- # [tps-game] 38 spawn points validated
32
- # [server] http://localhost:8080 @ 128 TPS
33
- # Client connects and receives continuous snapshots
15
+ ```
16
+ server.js Entry point, calls boot()
17
+ src/sdk/server.js Creates all subsystems, wires them together
18
+ src/sdk/TickHandler.js Per-tick: movement -> physics -> collisions -> app tick -> snapshot
19
+ src/sdk/ReloadManager.js File watchers for SDK hot reload
20
+ src/apps/AppRuntime.js Entity system, app lifecycle, timers, collision events
21
+ src/apps/AppLoader.js Loads apps from apps/ directory, validates, watches for changes
22
+ src/physics/World.js Jolt Physics wrapper (bodies, characters, raycasts)
23
+ src/netcode/PhysicsIntegration.js CharacterVirtual per player, gravity application
24
+ src/connection/ConnectionManager.js WebSocket client management, heartbeat, msgpack encode/decode
25
+ src/protocol/msgpack.js Hand-rolled msgpack encoder/decoder
26
+ client/app.js Three.js renderer, VRM loading, entity rendering, input loop
34
27
  ```
35
28
 
36
- ## Architecture
29
+ ## World Config
37
30
 
38
- **Server-Side (Physics + Netcode)**
39
- - Jolt Physics WASM for real rigid body simulation
40
- - 128 TPS fixed timestep via setImmediate loop
41
- - Binary msgpackr protocol over WebSocket
42
- - Automatic lag compensation and prediction
43
- - Hot reload support without disconnections
44
-
45
- **Client-Side (Display-Engine Agnostic)**
46
- - Receives position/rotation/velocity snapshots
47
- - Client-side input prediction
48
- - Server reconciliation blending
49
- - Display engine agnostic (works with THREE.js, Babylon, PlayCanvas, etc.)
50
-
51
- **Apps System**
52
- - Single-file app format: `server` + `client` object
53
- - Dynamic entity spawning and removal
54
- - App hot-reload with state persistence
55
- - Context API for physics, world, players, events
56
-
57
- ## File Structure (30 files, all under 200 lines)
58
-
59
- **Production Apps**
60
- - `apps/world/index.js` - World definition and spawn configuration
61
- - `apps/environment/index.js` - Static trimesh collider
62
- - `apps/interactive-door/index.js` - Proximity-based kinematic door
63
- - `apps/patrol-npc/index.js` - Waypoint-based NPC patrol
64
- - `apps/physics-crate/index.js` - Dynamic physics object
65
- - `apps/tps-game/index.js` - Full multiplayer TPS game
66
-
67
- **SDK Core (19 files)**
68
- - `src/physics/` - Jolt WASM integration
69
- - `src/netcode/` - Tick system, networking, snapshots
70
- - `src/client/` - Client prediction and reconciliation
71
- - `src/apps/` - App loader, runtime, context
72
- - `src/sdk/` - Server and client SDKs
73
- - `src/protocol/` - Message types and encoding
74
-
75
- ## Performance Verified
76
-
77
- | Metric | Target | Verified |
78
- |--------|--------|----------|
79
- | Startup | < 2 sec | ~1.8s ✓ |
80
- | First snapshot | < 1000ms | < 500ms ✓ |
81
- | Tick rate | 124+ TPS | 124-125 TPS ✓ |
82
- | Memory | Stable | Stable, no leaks ✓ |
83
- | Network | 70% compression | msgpackr verified ✓ |
84
- | Max players | 5+ | 5+ tested ✓ |
85
- | Max entities | 50+ | 50+ tested ✓ |
86
-
87
- ## Example Application
31
+ `apps/world/index.js` exports the world definition:
32
+
33
+ ```javascript
34
+ export default {
35
+ port: 8080,
36
+ tickRate: 128,
37
+ gravity: [0, -9.81, 0],
38
+ movement: { maxSpeed: 4.0, groundAccel: 10.0, airAccel: 1.0, friction: 6.0, stopSpeed: 2.0, jumpImpulse: 4.0 },
39
+ player: { health: 100, capsuleRadius: 0.4, capsuleHalfHeight: 0.9, mass: 120, modelScale: 1.323, feetOffset: 0.212 },
40
+ scene: { skyColor: 0x87ceeb, sunColor: 0xffffff, sunIntensity: 1.5, sunPosition: [21, 50, 20] },
41
+ camera: { fov: 70, shoulderOffset: 0.35, zoomStages: [0, 1.5, 3, 5, 8], defaultZoomIndex: 2 },
42
+ animation: { mixerTimeScale: 1.3, walkTimeScale: 2.0, sprintTimeScale: 0.56, fadeTime: 0.15 },
43
+ entities: [
44
+ { id: 'environment', model: './apps/tps-game/schwust.glb', position: [0, 0, 0], app: 'environment' },
45
+ { id: 'game', position: [0, 0, 0], app: 'tps-game' }
46
+ ],
47
+ playerModel: './apps/tps-game/Cleetus.vrm',
48
+ spawnPoint: [-35, 3, -65]
49
+ }
50
+ ```
51
+
52
+ ## Creating Apps
53
+
54
+ Create `apps/<name>/index.js`:
88
55
 
89
56
  ```javascript
90
- // apps/custom-game/index.js
91
57
  export default {
92
58
  server: {
93
59
  setup(ctx) {
94
- ctx.state.score = 0
95
- ctx.physics.setDynamic(true)
96
- ctx.physics.addBoxCollider([1, 1, 1])
60
+ // Called once on spawn and on hot reload
61
+ // ctx.state persists across hot reloads
62
+ ctx.state.counter = ctx.state.counter || 0
97
63
  },
98
64
  update(ctx, dt) {
99
- ctx.state.score += dt
65
+ // Called every tick (128/sec)
66
+ ctx.state.counter += dt
67
+ },
68
+ teardown(ctx) {
69
+ // Called on destroy or before hot reload
70
+ },
71
+ onMessage(ctx, msg) {
72
+ // Receives player_join, player_leave, fire, and custom APP_EVENT messages
73
+ if (msg.type === 'player_join') { /* ... */ }
74
+ },
75
+ onInteract(ctx, player) {
76
+ // Called when client sends APP_EVENT with this entity's ID
100
77
  },
101
78
  onCollision(ctx, other) {
102
- console.log('Hit:', other.id)
79
+ // Called when this entity's collider overlaps another entity's collider
103
80
  }
104
81
  },
105
82
  client: {
83
+ setup(engine) {
84
+ // engine.scene, engine.camera, engine.renderer, engine.THREE, engine.client, engine.cam
85
+ },
106
86
  render(ctx) {
87
+ // Return visual state. ctx.entity, ctx.state, ctx.h (createElement), ctx.engine, ctx.players
107
88
  return {
108
- model: ctx.entity.model,
109
89
  position: ctx.entity.position,
110
- rotation: ctx.entity.rotation,
111
- custom: { score: ctx.state.score }
90
+ custom: { mesh: 'box', color: 0xff0000, sx: 1, sy: 1, sz: 1 },
91
+ ui: ctx.h('div', {}, 'Hello')
112
92
  }
113
- }
93
+ },
94
+ onInput(input, engine) { },
95
+ onFrame(dt, engine) { },
96
+ onEvent(payload, engine) { },
97
+ onMouseDown(e, engine) { },
98
+ onMouseUp(e, engine) { }
114
99
  }
115
100
  }
116
101
  ```
117
102
 
118
- ## Dependencies
119
-
120
- - **jolt-physics** - Production physics engine
121
- - **msgpackr** - Binary encoding (70% smaller snapshots)
122
- - **ws** - WebSocket server
123
-
124
- ## Code Quality
125
-
126
- - All 30 source files under 200 lines
127
- - Zero code duplication
128
- - Zero hardcoded values (all config-driven)
129
- - Minimal logging (important events only)
130
- - No test files (real integration testing only)
131
- - Hot reload architecture mandatory
132
-
133
- ## Network Protocol
134
-
135
- **Binary Snapshot Format (msgpackr)**
136
- - Players: [id, px, py, pz, rx, ry, rz, rw, vx, vy, vz, onGround, health, inputSeq]
137
- - Entities: [id, model, px, py, pz, rx, ry, rz, rw, bodyType, custom]
138
- - Quantized for ~70% compression vs JSON
139
- - Broadcast every tick (128 per second)
140
-
141
- ## Display Engine Agnostic
142
-
143
- The SDK works with any display engine:
144
- - **THREE.js** - `position`, `rotation` apply directly to Object3D
145
- - **Babylon.js** - Maps to TransformNode properties
146
- - **PlayCanvas** - Native compatibility
147
- - **Custom engine** - Receive raw position/rotation/velocity data
148
-
149
- ## Creating Apps
150
-
151
- Apps are single-file modules with `server` and `client` objects:
103
+ ## Server-Side ctx API
104
+
105
+ | Property | Description |
106
+ |---|---|
107
+ | `ctx.state` | Persistent state object (survives hot reload) |
108
+ | `ctx.entity` | Entity proxy: `.id`, `.position`, `.rotation`, `.scale`, `.velocity`, `.custom`, `.destroy()` |
109
+ | `ctx.physics` | `.addBoxCollider(size)`, `.addSphereCollider(r)`, `.addCapsuleCollider(r, h)`, `.addTrimeshCollider()`, `.setDynamic(bool)`, `.addForce(vec3)`, `.setVelocity(vec3)` |
110
+ | `ctx.world` | `.spawn(id, cfg)`, `.destroy(id)`, `.attach(eid, app)`, `.getEntity(id)`, `.query(filter)`, `.nearby(pos, radius)` |
111
+ | `ctx.players` | `.getAll()`, `.getNearest(pos, r)`, `.send(pid, msg)`, `.broadcast(msg)`, `.setPosition(pid, pos)` |
112
+ | `ctx.time` | `.tick`, `.deltaTime`, `.elapsed`, `.after(sec, fn)`, `.every(sec, fn)` |
113
+ | `ctx.bus` | `.on(channel, fn)`, `.emit(channel, data)`, `.once(channel, fn)`, `.handover(targetEntityId, state)` |
114
+ | `ctx.network` | `.broadcast(msg)`, `.sendTo(id, msg)` |
115
+ | `ctx.storage` | `.get(key)`, `.set(key, val)`, `.delete(key)`, `.list(prefix)`, `.has(key)` |
116
+ | `ctx.config` | Entity config passed from world definition |
117
+ | `ctx.raycast(origin, dir, maxDist)` | Physics raycast against world geometry |
118
+
119
+ ## Client Engine API
120
+
121
+ | Property | Description |
122
+ |---|---|
123
+ | `engine.scene` | THREE.Scene |
124
+ | `engine.camera` | THREE.PerspectiveCamera |
125
+ | `engine.renderer` | THREE.WebGLRenderer |
126
+ | `engine.THREE` | Three.js module |
127
+ | `engine.client` | PhysicsNetworkClient instance |
128
+ | `engine.playerId` | Local player ID |
129
+ | `engine.cam` | Camera controller: `.yaw`, `.pitch`, `.getAimDirection(pos)`, `.setMode(m)`, `.applyConfig(cfg)` |
130
+ | `engine.players` | `.getMesh(id)`, `.getState(id)`, `.getAnimator(id)`, `.setExpression(id, name, val)` |
131
+ | `engine.createElement` | webjsx createElement for UI |
132
+
133
+ ## Entity Custom Mesh Properties
134
+
135
+ When an entity has no `model`, the client builds geometry from `entity.custom`:
136
+
137
+ | Field | Description |
138
+ |---|---|
139
+ | `mesh` | `'box'` (default), `'cylinder'`, `'sphere'` |
140
+ | `color` | Hex color (default 0xff8800) |
141
+ | `sx, sy, sz` | Box dimensions |
142
+ | `r` | Radius for sphere/cylinder |
143
+ | `h` | Height for cylinder |
144
+ | `spin` | Y-axis rotation speed (radians/sec) |
145
+ | `hover` | Vertical bob amplitude |
146
+ | `light` | PointLight color |
147
+ | `lightIntensity, lightRange` | PointLight params |
148
+ | `emissive, emissiveIntensity` | Material emissive |
149
+
150
+ ## EventBus Channels
151
+
152
+ Apps communicate via `ctx.bus`:
152
153
 
153
154
  ```javascript
154
- export default {
155
- server: {
156
- setup(ctx) { }, // Called once on app load
157
- update(ctx, dt) { }, // Called each tick
158
- teardown(ctx) { }, // Called on hot reload
159
- onCollision(ctx, other) { }, // Collision event
160
- onInteract(ctx, player) { }, // Proximity event
161
- onMessage(ctx, msg) { } // Custom messages
162
- },
163
- client: {
164
- render(ctx) { } // Return render data
165
- }
166
- }
167
- ```
155
+ // Publisher
156
+ ctx.bus.emit('combat.fire', { shooterId, origin, direction })
168
157
 
169
- Context (`ctx`) provides:
170
- - `ctx.entity` - Current entity data
171
- - `ctx.physics` - Physics API (gravity, colliders, forces)
172
- - `ctx.world` - World API (spawn, destroy, raycast)
173
- - `ctx.players` - Player API (list, nearest, send, broadcast)
174
- - `ctx.state` - Persistent app state (survives hot reload)
175
- - `ctx.time` - Tick, deltaTime, elapsed
176
- - `ctx.events` - Event emitter (emit, on, off)
177
- - `ctx.network` - Network API (broadcast, sendTo)
178
-
179
- ## Hot Reload
180
-
181
- Apps reload without disconnecting players:
182
- - Edit app file → Server detects change
183
- - TickSystem pauses for atomic reload
184
- - Old app teardown, new app setup
185
- - World state preserved
186
- - Clients notified but stay connected
187
- - Player input continues flowing
188
-
189
- ## WAVE 5 Verification Summary
190
-
191
- All systems verified production-ready:
192
-
193
- ✓ Cold boot test: Server starts in ~1.8 seconds
194
- ✓ Client connection: ws://localhost:8080/ws
195
- ✓ Snapshots: 128 TPS continuous delivery
196
- ✓ All 6 apps: Coexisting without conflicts
197
- ✓ TPS game: 38 spawn points validated via raycasting
198
- ✓ Hot reload: Working without disconnections
199
- ✓ Entity management: Live spawn/remove working
200
- ✓ Tick rate: 124-125 TPS verified
201
- ✓ Zero crashes: 30+ second test completed
202
- ✓ Memory: Stable, zero leaks
203
- ✓ Code quality: All < 200 lines per file
204
- ✓ Documentation: Complete in CLAUDE.md
205
-
206
- ## Getting Started
207
-
208
- ```bash
209
- # Install and start
210
- npm install
211
- node server.js
212
-
213
- # In another terminal
214
- node wave5-test.mjs
158
+ // Subscriber (supports wildcard)
159
+ ctx.bus.on('combat.*', (event) => {
160
+ // event.channel, event.data, event.meta.sourceEntity, event.meta.timestamp
161
+ })
215
162
  ```
216
163
 
217
- Expected output:
218
- ```
219
- [tps-game] 38 spawn points validated
220
- [server] http://localhost:8080 @ 128 TPS
221
- [WAVE5] Client connected to ws://localhost:8080/ws
222
- [WAVE5] World state received
223
- ... snapshots streaming at 128 TPS
224
- ```
164
+ Scoped subscriptions auto-cleanup on entity destroy/hot reload.
225
165
 
226
- ## Documentation
227
-
228
- Complete technical reference available in **CLAUDE.md**:
229
- - Architecture overview
230
- - Server tick system (128 TPS)
231
- - Physics engine (Jolt WASM)
232
- - Network protocol (binary msgpackr)
233
- - App system (single-file format)
234
- - Context API reference
235
- - Hot reload guarantees
236
- - Performance specifications
237
-
238
- ## Status
239
-
240
- **PRODUCTION READY** ✓
241
-
242
- The Spawnpoint SDK is fully verified and ready for deployment. All systems have been tested through comprehensive cold-boot validation, end-to-end functionality testing, and 30+ second stability verification.
243
-
244
- No known issues. Zero crashes. Zero memory leaks. Stable tick rate. Complete documentation.
166
+ ## Dependencies
245
167
 
246
- Ready for production use.
168
+ - `jolt-physics` - WASM physics engine
169
+ - `ws` - WebSocket server
170
+ - `webjsx` - JSX-like DOM diffing for client UI
171
+ - `d3-octree` - Spatial indexing
247
172
 
248
173
  ## License
249
174
 
250
- GPL-3.0-only
175
+ MIT
package/SKILL.md ADDED
@@ -0,0 +1,95 @@
1
+ ---
2
+ name: spoint
3
+ description: Work with spoint - a multiplayer physics game server SDK. Scaffolds apps locally, runs engine from npm package.
4
+ ---
5
+
6
+ # spoint
7
+
8
+ You are helping a developer work with the spoint multiplayer game server SDK.
9
+
10
+ ## Setup (First Time)
11
+
12
+ When no `apps/` directory exists in the current working directory, scaffold it:
13
+
14
+ ```bash
15
+ bunx spoint scaffold
16
+ bunx spoint
17
+ ```
18
+
19
+ This copies the default apps (world config, tps-game, environment, etc.) into `./apps/` and starts the server. The engine (src/, client/) always comes from the npm package - never from the user's local folder.
20
+
21
+ ## Daily Use
22
+
23
+ ```bash
24
+ bunx spoint # start server (port 3001, 128 TPS)
25
+ ```
26
+
27
+ Open http://localhost:3001 in browser. Apps hot-reload on file save.
28
+
29
+ ## Creating Apps
30
+
31
+ ```bash
32
+ bunx spoint-create-app my-app
33
+ bunx spoint-create-app --template physics my-physics-object
34
+ bunx spoint-create-app --template interactive my-button
35
+ bunx spoint-create-app --template spawner my-spawner
36
+ ```
37
+
38
+ ## App Structure
39
+
40
+ Apps live in `apps/<name>/index.js` and export a default object:
41
+
42
+ ```js
43
+ export default {
44
+ server: {
45
+ setup(ctx) {
46
+ ctx.entity.custom = { mesh: 'box', color: 0x00ff00 }
47
+ ctx.physics.setStatic(true)
48
+ ctx.physics.addBoxCollider([0.5, 0.5, 0.5])
49
+ },
50
+ update(ctx, dt) {},
51
+ teardown(ctx) {}
52
+ },
53
+ client: {
54
+ render(ctx) {
55
+ return { position: ctx.entity.position, rotation: ctx.entity.rotation, custom: ctx.entity.custom }
56
+ }
57
+ }
58
+ }
59
+ ```
60
+
61
+ ## World Config
62
+
63
+ Edit `apps/world/index.js` to configure port, tickRate, gravity, movement, entities, and scene. The `entities` array auto-spawns apps on start.
64
+
65
+ ## Key Facts
66
+
67
+ - Engine files (src/, client/) come from the npm package - never edit them
68
+ - Only `apps/` is local to the user's project (their CWD)
69
+ - `ctx.state` survives hot reload; timers and bus subscriptions do not
70
+ - 128 TPS server, 60Hz client input, exponential lerp interpolation
71
+
72
+ ## Physics
73
+
74
+ ```js
75
+ // Static
76
+ ctx.physics.setStatic(true)
77
+ ctx.physics.addBoxCollider([halfX, halfY, halfZ])
78
+
79
+ // Dynamic
80
+ ctx.physics.setDynamic(true)
81
+ ctx.physics.setMass(5)
82
+ ```
83
+
84
+ ## EventBus
85
+
86
+ ```js
87
+ ctx.bus.on('combat.hit', (data) => {})
88
+ ctx.bus.emit('combat.hit', { damage: 10 })
89
+ // Wildcard: 'combat.*' catches all combat.* events
90
+ ```
91
+
92
+ ## Debugging
93
+
94
+ - Server: `globalThis.__DEBUG__.server` in Node REPL
95
+ - Client: `window.debug` in browser console (exposes scene, camera, renderer, client)