sloptimize 0.3.0

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.
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "sloptimize",
3
+ "owner": { "name": "m0dE" },
4
+ "plugins": [
5
+ {
6
+ "name": "sloptimize",
7
+ "source": "./",
8
+ "description": "The agent-native profiler for three.js games: always-on incident recording, zero-setup attach with file:line attribution, budgets with exit codes."
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "sloptimize",
3
+ "displayName": "sloptimize",
4
+ "version": "0.3.0",
5
+ "description": "The agent-native profiler for browser games: always-on incident recording, zero-setup attach with file:line attribution, budgets with exit codes — the agent's senses and ruler for performance work.",
6
+ "license": "MIT",
7
+ "keywords": ["profiler", "three.js", "webgpu", "performance", "draw-calls"]
8
+ }
package/.mcp.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "mcpServers": {
3
+ "sloptimize": {
4
+ "type": "stdio",
5
+ "command": "node",
6
+ "args": ["${CLAUDE_PLUGIN_ROOT}/mcp/server.mjs"]
7
+ }
8
+ }
9
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Moddio
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,263 @@
1
+ # sloptimize
2
+
3
+ sloptimize optimizes your game's rendering performance by finding the
4
+ bottlenecks and reporting them to Claude Code to fix — all while you just play
5
+ the game. No action is required on your end.
6
+
7
+ **The agent-native profiler for browser games.** Your coding agent cannot
8
+ watch a game run — it will never feel a hitch, cannot screenshot 60 times a
9
+ second, and cannot verify a "fix" it cannot measure. sloptimize gives the
10
+ agent the three verbs it measurably lacks:
11
+
12
+ - **MEASURE** — an always-on flight recorder detects incidents (CPU spikes,
13
+ fps drops, GPU stalls, and the player's unit or camera SNAPPING off its own
14
+ trajectory) automatically, in the background, and writes them to disk
15
+ before anyone asks. The human just plays.
16
+ - **ATTRIBUTE** — every incident arrives classified with evidence
17
+ (`shader-compile: programs +2`, `long-script`, upload storms,
18
+ `snap 17.5m in one frame`), stamped with a **footprint** — the identity of
19
+ its cause and the game's situation (which machine, at the helm or on foot,
20
+ in combat…), never its time — so one cause across builds, sessions and
21
+ players is one issue with a count and a fix history, and — with the attach
22
+ tier — named by **function and file:line** from a rolling sampling profiler.
23
+ - **VERIFY** — exact counters (draw calls, triangles, pipelines — deterministic
24
+ on any renderer), perf budgets with exit codes, and honest labels: timing
25
+ numbers carry their regime (`hardware`/`software`) and are never compared
26
+ across them.
27
+
28
+ The division of labor is the design: **the tool decides what is true; the
29
+ agent decides what to try; the human plays.**
30
+
31
+ Proven in production on a 149k-line WebGPU battle-royale: the pipeline caught
32
+ a 205,000-calls/11s GPU upload storm from a player's real session, attributed
33
+ it, and verified the fix at >60× reduction — with the player doing nothing
34
+ but playing.
35
+
36
+ ## The pipeline
37
+
38
+ ```
39
+ game/browser ──► incidents (auto-detected, classified, clustered)
40
+
41
+
42
+ .sloptimize/ ◄── the agent's reading room
43
+ profile.json rolling summary (median/p95/counters/regime)
44
+ perf.jsonl incident records, append-only, each with its footprint
45
+ clusters.json one cause = one cluster
46
+ census.json per-entity cost census (tier 1+)
47
+ fixes.jsonl the fix ledger: issue → solution, commit, MEASURED before/after
48
+ budgets.json YOUR limits (the one human-authored file)
49
+
50
+ ┌───────────┴───────────┐
51
+ ▼ ▼
52
+ Claude Code (agent) in-game debugger (human, OPTIONAL)
53
+ woken on new incidents Session · Issues · Optimizations · Settings —
54
+ (fp=<id> ×N on each); this tab's incidents + a note box; every cause
55
+ reads, fixes, verifies, grouped by footprint with ×N, last seen and the
56
+ records each fix fixes applied; p95/calls/hitches over time
57
+ ```
58
+
59
+ Showing the work is part of the loop: after a verified fix the agent runs
60
+ `sloptimize fix --title … --issue … --solution … --commit <sha>`, and the
61
+ record's before/after are two **measured** windows of the ledger (previous
62
+ build vs new build) — not numbers the agent typed. The debugger's Fixes tab
63
+ and `sloptimize history` read that ledger back.
64
+
65
+ ## Install
66
+
67
+ ```bash
68
+ npm i -D sloptimize # in your game repo
69
+ # or one-off: npx sloptimize attach --launch http://localhost:3000
70
+ # or from a checkout: node sloptimize/bin/sloptimize.mjs … (bare Node, no install)
71
+ ```
72
+
73
+ Zero dependencies, no postinstall, no supply chain — npm is delivery only.
74
+
75
+ ## Quickest start: zero integration (tier 0)
76
+
77
+ Requires only Node 22+ and a Chromium. No game changes, no build changes:
78
+
79
+ ```bash
80
+ npx sloptimize attach --launch http://localhost:3000 --headless
81
+ # play / drive the game …then:
82
+ npx sloptimize report
83
+ ```
84
+
85
+ Attach connects over the Chrome DevTools Protocol, injects a recorder before
86
+ any page script (rAF timing, draw/triangle counts via graphics-API wraps,
87
+ pipeline creations WITH call stacks, upload bytes, GPU queue latency), and
88
+ runs a rolling sampling profiler so a freeze is attributed like:
89
+
90
+ ```
91
+ INCIDENT long-script|seededFreezeWork@game.js:512 — 900ms
92
+ ```
93
+
94
+ Limits, stated: Chromium-only; minified bundles attribute to minified names
95
+ unless you serve sourcemaps; entity-level attribution needs tier 1+.
96
+
97
+ ## Higher fidelity: the in-page feed (tier 1)
98
+
99
+ One call per frame from wherever your loop already reads `renderer.info`:
100
+
101
+ ```js
102
+ import { createRecorder } from 'sloptimize';
103
+ const rec = createRecorder({ budgetFrameMs: 16.7 });
104
+ // per frame:
105
+ rec.frame({ frameMs, insideRenderMs, calls, triangles, programs,
106
+ geometries, textures, spawned, paused });
107
+ // optional human channel (bind to a chord, e.g. Ctrl+F11):
108
+ rec.usermark({ windowMs: 5000, note, inputsHeld, world });
109
+ ```
110
+
111
+ Ship the records to `.sloptimize/` however your stack likes — a vite host
112
+ gets a plugin (planned); any other host adds one dev-gated POST endpoint
113
+ (~100 lines; see `docs/INTEGRATION.md` for the reference implementation,
114
+ including the four traps that cost the first deployment real time:
115
+ **don't gate activation on hostname** (probe your dev endpoint instead),
116
+ **give the recorder its own rAF clock** (a game-loop-fed clock is blind to
117
+ boot/launch — exactly the windows you care about), **frameMs must bound
118
+ insideRenderMs**, and **never let the feed die silently** (retry the probe
119
+ and the posts on a backoff, buffer while dark, and SHOW the state — the
120
+ first deployment lost an hour of real freezes to a server restart that
121
+ dropped the ingest with no indication anywhere).
122
+
123
+ The wire contract the reference runtime keeps, so the files are useful on
124
+ their own:
125
+ - **every record is self-sufficient** — `build` (which bundle the tab runs)
126
+ and `phase` (menu/boot/launch/match…) ride each ledger line; hitches are
127
+ stamped at mint time, not post time;
128
+ - **a heartbeat record lands once a minute while armed**, so a quiet
129
+ `perf.jsonl` means "no session, or the feed is dark" — never just "idle"
130
+ (`sloptimize hook-status` warns when the ledger goes stale);
131
+ - **gpu-settle records** report how long a boot/reveal gate actually waited
132
+ on `onSubmittedWorkDone` — the on-hardware verification channel for
133
+ compile-stall fixes;
134
+ - **a hitch that overlapped pipeline/shader creates carries `createStacks`**
135
+ — the top 3 deduped `Error().stack` tails from the create wrappers (~2KB
136
+ cap), so a `programs +N` hitch from a machine you cannot profile names its
137
+ own call sites. The positions are minified (`bundle.js:L:C`); keep an
138
+ unreferenced sourcemap at build time and decode locally (the game repo's
139
+ `tools/decode-perf-stack.mjs` is a dependency-free reference decoder).
140
+
141
+ **Coordinate jitter and the issue catalogue** (tier 1, ~200 lines in the
142
+ game): feed the unit's and the camera's positions once per rendered frame
143
+ and a snap or oscillation lands as a classified `jitter` record; declare a
144
+ few facets of the player's situation and every incident of every kind is
145
+ footprinted, counted and linked to its fixes — the debugger's **Issues**
146
+ tab, `sloptimize issues`, and `fp=<id> ×N` on every wake line. The whole
147
+ recipe, with the three traps that make a naive position detector lie
148
+ (rotation, transient shakes, the sim's dt clamp), is
149
+ `docs/JITTER-AND-FOOTPRINTS.md`.
150
+
151
+ ```js
152
+ import { createMotionMonitor, canonicalContext, footprintOf } from 'sloptimize';
153
+ const motion = createMotionMonitor({ unit: 'm', longFrameMs: 50,
154
+ tracks: { unit: { floor: 0.1 }, camera: { floor: 0.1, reach: 'boom', follows: 'unit' } } });
155
+ // per rendered frame, after the render:
156
+ motion.sample('unit', pivot.x, pivot.y, pivot.z, now, { held: paused, phase, ctx });
157
+ motion.sample('camera', cam.x, cam.y, cam.z, now, { held: paused || lookInput, reach, phase, ctx });
158
+ // once a second: ctx = canonicalContext({ stance: 'helm', hull: 'elong-x', squad: 'duo', combat: 'no' });
159
+ // at post: for (const r of records) { r.ctx ??= ctx; const fp = footprintOf(r); if (fp) r.footprint = fp; }
160
+ ```
161
+
162
+ Tier 2 (scene census, per-entity attribution, measured bisection) layers on
163
+ top where the engine grants scene access — see `docs/SPEC.md` §4.
164
+
165
+ ## Claude Code integration — the whole point
166
+
167
+ This repo IS a Claude Code plugin. One install:
168
+
169
+ ```bash
170
+ claude --plugin-dir node_modules/sloptimize # after npm i -D sloptimize
171
+ claude --plugin-dir /path/to/sloptimize # from a checkout
172
+ # or via marketplace: /plugin marketplace add m0dE/sloptimize && /plugin install sloptimize
173
+ ```
174
+
175
+ Then let the agent wire your game: `/sloptimize:install` walks it through
176
+ the tier-1 integration (runtime, sink, budgets, hooks) and refuses to call
177
+ itself done until the feed is proven live end-to-end.
178
+
179
+ That carries three surfaces into every session:
180
+ - **Skill** — the doctrine: read → classify → census → ONE change → verify
181
+ with counters; never claim a perf fix without a measured before/after;
182
+ never quote timing from a software regime.
183
+ - **Prompt hook** — silent by default; when a NEW keyframe or budget breach
184
+ exists, up to five lines land in the agent's context on your next prompt.
185
+ - **MCP server** — `get_report`, `check_budgets`, `get_history`,
186
+ `get_issues` (the catalogue by footprint), `record_fix` (with the
187
+ footprints it addresses), and `attach_start` / `attach_stop` for the live
188
+ tier.
189
+
190
+ For instant wakeups (the agent starts fixing ~20s after the stutter, no
191
+ prompt needed), arm `sloptimize watch` as a session Monitor — one line, in
192
+ `docs/INTEGRATION.md` §5. Wire it into a `SessionStart` hook and every
193
+ session arms it by itself.
194
+
195
+ ## Budgets: "fast enough" as an exit code
196
+
197
+ `.sloptimize/budgets.json` (the one file a human reviews):
198
+
199
+ ```json
200
+ { "perf.budget.draw_calls": 400, "perf.budget.frame_ms_p95": 16.7 }
201
+ ```
202
+
203
+ ```bash
204
+ npx sloptimize check # exit 0 inside · 1 breached · 4 unmeasured
205
+ ```
206
+
207
+ That exit code is what lets an agent self-iterate in a loop that terminates.
208
+
209
+ ## CLI
210
+
211
+ ```
212
+ sloptimize report current profile + incidents + census hints
213
+ sloptimize check budgets → exit code (--counters-only for CI)
214
+ sloptimize census per-entity costs + closed-vocabulary hints
215
+ sloptimize history the timeline: p95 / draw calls / hitches per time
216
+ bucket and per build, plus the fix ledger
217
+ sloptimize fix record a verified fix (title, issue, solution,
218
+ commit) with MEASURED before/after windows
219
+ sloptimize attach tier-0: --launch <url> [--headless] [--port N]
220
+ sloptimize hook-status the prompt hook's ≤5-line ambient surface
221
+ sloptimize issues the catalogue: every incident grouped by FOOTPRINT
222
+ (cause + situation, never time) — how often, how
223
+ recently, which fixes were applied; --fp <id> for one
224
+ sloptimize watch the push channel: one stdout line per usermark /
225
+ ≥100ms hitch / gpu cap-hit / coordinate jitter /
226
+ feed dark, each with fp=<id> ×N; never exits
227
+ sloptimize doctor what is wired, what is degraded, stated limits
228
+ ```
229
+
230
+ ## What it will tell you it cannot do
231
+
232
+ Printed by `doctor`, kept in the spec, never silently degraded: no per-draw
233
+ GPU timing; bisection ranks rather than sums; workload repro, not trajectory
234
+ repro; timing from software renderers flagged and never compared; V8
235
+ inlining can split an incident cluster across an optimization boundary;
236
+ **correctness bugs are out of scope** — a profiler cannot find a logic bug,
237
+ and the doctrine routes "it looks/behaves wrong" reports away before anyone
238
+ burns a loop on them.
239
+
240
+ ## Docs
241
+
242
+ - `docs/USAGE.md` — day-to-day use once wired: the operator's verbs, new-session pickup, multi-session semantics, monitoring options
243
+ - `docs/SPEC.md` — the founding specification (recorder, census, bench, anti-gaming posture)
244
+ - `docs/SPEC-attach.md` — v2: the incident pipeline, tier-0 attach, measured exit criteria
245
+ - `docs/INTEGRATION.md` — wiring a real game + Claude Code session, with the reference deployment's traps
246
+ - `docs/DESIGN-mecharoyale-v0.md` — the first field deployment's decision record
247
+
248
+ ## Status
249
+
250
+ M0–M2 (recorder, census, budgets/CLI) and M-A0–A2 (attach, incident
251
+ identity, plugin packaging) shipped with measured exit criteria. Bench +
252
+ correctness gate (SPEC §6, M3) and paused-world bisection (M4) are next.
253
+
254
+ ## Relationship to slopjs
255
+
256
+ A sibling on the same platform: slopjs is a pointing device for a
257
+ human-in-the-loop authoring session; sloptimize is a measurement loop that
258
+ works with nobody watching. Tier 2 consumes `@slopjs/inspector` primitives
259
+ (stable IDs, the coherent pause, snapshots) where present.
260
+
261
+ ## License
262
+
263
+ MIT