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.
- package/README.md +134 -209
- package/SKILL.md +95 -0
- package/apps/environment/index.js +200 -1
- package/apps/environment/models/decorative/.gitkeep +0 -0
- package/apps/environment/models/hazards/.gitkeep +0 -0
- package/apps/environment/models/interactive/.gitkeep +0 -0
- package/apps/environment/models/structures/.gitkeep +0 -0
- package/apps/environment/smartObjects.js +114 -0
- package/apps/interactable/index.js +155 -0
- package/apps/physics-crate/index.js +15 -9
- package/apps/power-crate/index.js +18 -12
- package/apps/tps-game/$GDUPI.vrm +0 -0
- package/apps/tps-game/Cleetus.vrm +0 -0
- package/apps/tps-game/index.js +185 -27
- package/apps/world/index.js +68 -22
- package/bin/create-app.js +337 -0
- package/client/ARControls.js +301 -0
- package/client/LoadingManager.js +117 -0
- package/client/MobileControls.js +1122 -0
- package/client/anim-lib.glb +0 -0
- package/client/animation.js +306 -0
- package/client/app.js +1341 -65
- package/client/camera.js +191 -33
- package/client/createLoadingScreen.js +69 -0
- package/client/editor/bridge.js +113 -0
- package/client/editor/css/main.css +794 -0
- package/client/editor/images/rotate.svg +4 -0
- package/client/editor/images/scale.svg +4 -0
- package/client/editor/images/translate.svg +4 -0
- package/client/editor/index.html +103 -0
- package/client/editor/js/Command.js +41 -0
- package/client/editor/js/Config.js +81 -0
- package/client/editor/js/Editor.js +785 -0
- package/client/editor/js/EditorControls.js +438 -0
- package/client/editor/js/History.js +321 -0
- package/client/editor/js/Loader.js +987 -0
- package/client/editor/js/LoaderUtils.js +90 -0
- package/client/editor/js/Menubar.Add.js +510 -0
- package/client/editor/js/Menubar.Edit.js +145 -0
- package/client/editor/js/Menubar.File.js +466 -0
- package/client/editor/js/Menubar.Help.js +73 -0
- package/client/editor/js/Menubar.Status.js +51 -0
- package/client/editor/js/Menubar.View.js +183 -0
- package/client/editor/js/Menubar.js +27 -0
- package/client/editor/js/Player.js +53 -0
- package/client/editor/js/Resizer.js +58 -0
- package/client/editor/js/Script.js +503 -0
- package/client/editor/js/Selector.js +102 -0
- package/client/editor/js/Sidebar.Geometry.BoxGeometry.js +121 -0
- package/client/editor/js/Sidebar.Geometry.BufferGeometry.js +115 -0
- package/client/editor/js/Sidebar.Geometry.CapsuleGeometry.js +97 -0
- package/client/editor/js/Sidebar.Geometry.CircleGeometry.js +97 -0
- package/client/editor/js/Sidebar.Geometry.CylinderGeometry.js +121 -0
- package/client/editor/js/Sidebar.Geometry.DodecahedronGeometry.js +73 -0
- package/client/editor/js/Sidebar.Geometry.ExtrudeGeometry.js +196 -0
- package/client/editor/js/Sidebar.Geometry.IcosahedronGeometry.js +73 -0
- package/client/editor/js/Sidebar.Geometry.LatheGeometry.js +98 -0
- package/client/editor/js/Sidebar.Geometry.Modifiers.js +73 -0
- package/client/editor/js/Sidebar.Geometry.OctahedronGeometry.js +74 -0
- package/client/editor/js/Sidebar.Geometry.PlaneGeometry.js +97 -0
- package/client/editor/js/Sidebar.Geometry.RingGeometry.js +121 -0
- package/client/editor/js/Sidebar.Geometry.ShapeGeometry.js +76 -0
- package/client/editor/js/Sidebar.Geometry.SphereGeometry.js +133 -0
- package/client/editor/js/Sidebar.Geometry.TetrahedronGeometry.js +74 -0
- package/client/editor/js/Sidebar.Geometry.TorusGeometry.js +109 -0
- package/client/editor/js/Sidebar.Geometry.TorusKnotGeometry.js +121 -0
- package/client/editor/js/Sidebar.Geometry.TubeGeometry.js +135 -0
- package/client/editor/js/Sidebar.Geometry.js +332 -0
- package/client/editor/js/Sidebar.Material.BooleanProperty.js +60 -0
- package/client/editor/js/Sidebar.Material.ColorProperty.js +87 -0
- package/client/editor/js/Sidebar.Material.ConstantProperty.js +62 -0
- package/client/editor/js/Sidebar.Material.MapProperty.js +249 -0
- package/client/editor/js/Sidebar.Material.NumberProperty.js +60 -0
- package/client/editor/js/Sidebar.Material.Program.js +73 -0
- package/client/editor/js/Sidebar.Material.RangeValueProperty.js +63 -0
- package/client/editor/js/Sidebar.Material.js +751 -0
- package/client/editor/js/Sidebar.Object.Animation.js +102 -0
- package/client/editor/js/Sidebar.Object.js +898 -0
- package/client/editor/js/Sidebar.Project.App.js +165 -0
- package/client/editor/js/Sidebar.Project.Image.js +225 -0
- package/client/editor/js/Sidebar.Project.Materials.js +82 -0
- package/client/editor/js/Sidebar.Project.Renderer.js +144 -0
- package/client/editor/js/Sidebar.Project.Video.js +242 -0
- package/client/editor/js/Sidebar.Project.js +31 -0
- package/client/editor/js/Sidebar.Properties.js +73 -0
- package/client/editor/js/Sidebar.Scene.js +585 -0
- package/client/editor/js/Sidebar.Script.js +129 -0
- package/client/editor/js/Sidebar.Settings.History.js +146 -0
- package/client/editor/js/Sidebar.Settings.Shortcuts.js +175 -0
- package/client/editor/js/Sidebar.Settings.js +60 -0
- package/client/editor/js/Sidebar.js +41 -0
- package/client/editor/js/Storage.js +98 -0
- package/client/editor/js/Strings.js +2028 -0
- package/client/editor/js/Toolbar.js +84 -0
- package/client/editor/js/Viewport.Controls.js +92 -0
- package/client/editor/js/Viewport.Info.js +136 -0
- package/client/editor/js/Viewport.Pathtracer.js +91 -0
- package/client/editor/js/Viewport.ViewHelper.js +39 -0
- package/client/editor/js/Viewport.XR.js +222 -0
- package/client/editor/js/Viewport.js +900 -0
- package/client/editor/js/commands/AddObjectCommand.js +68 -0
- package/client/editor/js/commands/AddScriptCommand.js +75 -0
- package/client/editor/js/commands/Commands.js +23 -0
- package/client/editor/js/commands/MoveObjectCommand.js +111 -0
- package/client/editor/js/commands/MultiCmdsCommand.js +85 -0
- package/client/editor/js/commands/RemoveObjectCommand.js +88 -0
- package/client/editor/js/commands/RemoveScriptCommand.js +81 -0
- package/client/editor/js/commands/SetColorCommand.js +73 -0
- package/client/editor/js/commands/SetGeometryCommand.js +87 -0
- package/client/editor/js/commands/SetGeometryValueCommand.js +70 -0
- package/client/editor/js/commands/SetMaterialColorCommand.js +86 -0
- package/client/editor/js/commands/SetMaterialCommand.js +79 -0
- package/client/editor/js/commands/SetMaterialMapCommand.js +143 -0
- package/client/editor/js/commands/SetMaterialRangeCommand.js +91 -0
- package/client/editor/js/commands/SetMaterialValueCommand.js +90 -0
- package/client/editor/js/commands/SetMaterialVectorCommand.js +79 -0
- package/client/editor/js/commands/SetPositionCommand.js +84 -0
- package/client/editor/js/commands/SetRotationCommand.js +84 -0
- package/client/editor/js/commands/SetScaleCommand.js +84 -0
- package/client/editor/js/commands/SetSceneCommand.js +103 -0
- package/client/editor/js/commands/SetScriptValueCommand.js +80 -0
- package/client/editor/js/commands/SetShadowValueCommand.js +73 -0
- package/client/editor/js/commands/SetUuidCommand.js +70 -0
- package/client/editor/js/commands/SetValueCommand.js +75 -0
- package/client/editor/js/libs/acorn/acorn.js +3236 -0
- package/client/editor/js/libs/acorn/acorn_loose.js +1299 -0
- package/client/editor/js/libs/acorn/walk.js +344 -0
- package/client/editor/js/libs/app/index.html +57 -0
- package/client/editor/js/libs/app.js +251 -0
- package/client/editor/js/libs/codemirror/addon/dialog.css +32 -0
- package/client/editor/js/libs/codemirror/addon/dialog.js +163 -0
- package/client/editor/js/libs/codemirror/addon/show-hint.css +36 -0
- package/client/editor/js/libs/codemirror/addon/show-hint.js +529 -0
- package/client/editor/js/libs/codemirror/addon/tern.css +87 -0
- package/client/editor/js/libs/codemirror/addon/tern.js +750 -0
- package/client/editor/js/libs/codemirror/codemirror.css +344 -0
- package/client/editor/js/libs/codemirror/codemirror.js +9849 -0
- package/client/editor/js/libs/codemirror/mode/glsl.js +233 -0
- package/client/editor/js/libs/codemirror/mode/javascript.js +959 -0
- package/client/editor/js/libs/codemirror/theme/monokai.css +41 -0
- package/client/editor/js/libs/esprima.js +6401 -0
- package/client/editor/js/libs/jsonlint.js +453 -0
- package/client/editor/js/libs/signals.min.js +14 -0
- package/client/editor/js/libs/tern-threejs/threejs.js +5031 -0
- package/client/editor/js/libs/ternjs/comment.js +87 -0
- package/client/editor/js/libs/ternjs/def.js +588 -0
- package/client/editor/js/libs/ternjs/doc_comment.js +401 -0
- package/client/editor/js/libs/ternjs/infer.js +1635 -0
- package/client/editor/js/libs/ternjs/polyfill.js +80 -0
- package/client/editor/js/libs/ternjs/signal.js +26 -0
- package/client/editor/js/libs/ternjs/tern.js +993 -0
- package/client/editor/js/libs/ui.js +1346 -0
- package/client/editor/js/libs/ui.three.js +855 -0
- package/client/facial-animation.js +455 -0
- package/client/index.html +7 -4
- package/client/loading.css +147 -0
- package/client/loading.html +25 -0
- package/client/style.css +251 -0
- package/package.json +7 -3
- package/server.js +9 -1
- package/src/apps/AppContext.js +1 -1
- package/src/apps/AppLoader.js +50 -37
- package/src/apps/AppRuntime.js +32 -8
- package/src/client/InputHandler.js +233 -0
- package/src/client/JitterBuffer.js +207 -0
- package/src/client/KalmanFilter.js +125 -0
- package/src/client/MessageHandler.js +101 -0
- package/src/client/PhysicsNetworkClient.js +141 -68
- package/src/client/ReconnectManager.js +62 -0
- package/src/client/SmoothInterpolation.js +127 -0
- package/src/client/SnapshotProcessor.js +144 -0
- package/src/connection/ConnectionManager.js +21 -3
- package/src/connection/SessionStore.js +13 -3
- package/src/index.client.js +4 -6
- package/src/netcode/EventLog.js +29 -15
- package/src/netcode/LagCompensator.js +25 -26
- package/src/netcode/NetworkState.js +4 -1
- package/src/netcode/PhysicsIntegration.js +20 -6
- package/src/netcode/PlayerManager.js +10 -2
- package/src/netcode/SnapshotEncoder.js +66 -19
- package/src/netcode/TickSystem.js +13 -4
- package/src/physics/World.js +66 -13
- package/src/protocol/msgpack.js +90 -63
- package/src/sdk/ReloadHandlers.js +12 -2
- package/src/sdk/ReloadManager.js +5 -0
- package/src/sdk/ServerHandlers.js +50 -11
- package/src/sdk/StaticHandler.js +22 -6
- package/src/sdk/TickHandler.js +101 -34
- package/src/sdk/scaffold.js +31 -0
- package/src/sdk/server.js +59 -33
- package/src/shared/movement.js +2 -1
- package/src/spatial/Octree.js +5 -0
- package/apps/interactive-door/index.js +0 -33
- package/apps/patrol-npc/index.js +0 -37
- package/src/connection/QualityMonitor.js +0 -46
- package/src/debug/StateInspector.js +0 -42
- package/src/index.js +0 -1
- package/src/index.server.js +0 -27
- package/src/protocol/Codec.js +0 -60
- package/src/protocol/SequenceTracker.js +0 -71
- package/src/sdk/ClientMessageHandler.js +0 -80
- package/src/sdk/client.js +0 -122
- package/world/kaira.glb +0 -0
- package/world/schwust.glb +0 -0
package/README.md
CHANGED
|
@@ -1,250 +1,175 @@
|
|
|
1
|
-
# Spawnpoint
|
|
1
|
+
# Spawnpoint
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
28
|
-
node wave5-test.mjs
|
|
13
|
+
## Architecture
|
|
29
14
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
##
|
|
29
|
+
## World Config
|
|
37
30
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
95
|
-
ctx.
|
|
96
|
-
ctx.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
111
|
-
|
|
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
|
-
##
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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
|
-
|
|
155
|
-
|
|
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
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
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)
|