debug-visualization skill
scriptsUse when creating any game or interactive toy, when adding gameplay/UI features to one, when the builder asks for value tweaks in any language (too fast/slow, too big/small, a bit more/less, move it left/right/up/down, can't hit it, my tap doesn't register, hitbox, feels floaty/heavy/off, easier/harder, change X from N to M, 'don't rebuild — just fix this'; 너무 빨라요/느려요, 버튼이 안 눌려요, 판정이 이상해요, 히트박스, 이것만 고쳐줘), or when a message contains a [TUNING] or [ERRORS] block. Once loaded, stays in force for every subsequent message in the session without being re-mentioned. Ships a live in-game tuning panel with every game so builders adjust values themselves instead of burning chat round-trips.
- GitHub stars
- 7
- Files
- 2
- Last commit
- Sep 7, 2026
- License
- —
- Allowed tools
- —
What does the debug-visualization skill do?
debug-visualization uses when creating any game or interactive toy, when adding gameplay/UI features to one, when the builder asks for value tweaks in any language (too fast/slow, too big/small, a bit more/less, move it left/right/up/down, can't hit it, my tap doesn't register, hitbox, feels floaty/heavy/off, easier/harder, change X from N to M, 'don't rebuild — just fix this'; 너무 빨라요/느려요, 버튼이 안 눌려요, 판정이 이상해요, 히트박스, 이것만 고쳐줘), or when a message contains a [TUNING] or [ERRORS] block. Once loaded, stays in force for every subsequent message in the session without being re-mentioned. Ships a live in-game tuning panel with every game so builders adjust values themselves instead of burning chat round-trips.
How to install the debug-visualization skill
Each command copies the skill folder into the client's skills directory. Restart the client or start a new session to load it.Install the debug-visualization skill in Plugin
/plugin marketplace add NEXPACE-Limited/msu-skills /plugin install game-tools@msu-skills
Install the debug-visualization skill in Claude Code
~/.claude/skills/debug-visualization/SKILL.md
$ npx degit NEXPACE-Limited/msu-skills/plugins/game-tools/skills/debug-visualization ~/.claude/skills/debug-visualizationInstall the debug-visualization skill in Claude Code (project)
.claude/skills/debug-visualization/SKILL.md
$ npx degit NEXPACE-Limited/msu-skills/plugins/game-tools/skills/debug-visualization .claude/skills/debug-visualizationInstall the debug-visualization skill in Codex
~/.agents/skills/debug-visualization/SKILL.md
$ npx degit NEXPACE-Limited/msu-skills/plugins/game-tools/skills/debug-visualization ~/.agents/skills/debug-visualizationInstall the debug-visualization skill in Gemini CLI
~/.gemini/skills/debug-visualization/SKILL.md
$ npx degit NEXPACE-Limited/msu-skills/plugins/game-tools/skills/debug-visualization ~/.gemini/skills/debug-visualizationInstall the debug-visualization skill in Claude.ai
npx degit NEXPACE-Limited/msu-skills/plugins/game-tools/skills/debug-visualization debug-visualization && zip -r debug-visualization.zip debug-visualization # claude.ai → Customize → Skills → + → Create skill → Upload a skill → debug-visualization.zip
SKILL.md
View on GitHubGame Tuning Panel — build it with every game, unasked
Builders lose most of their build time to tiny tuning round-trips: "a bit faster", "move the button left", "make the hitbox bigger" — each one a full chat cycle for what should be a 2-second slider drag. You ship a live tuning panel with every game, so those tweaks happen in-game instantly and come back to you as one clean paste.
If you remember nothing else
- Every game gets the panel, unasked. The builder will not request it and may not know such a thing can exist. Build it anyway, every time.
- Every gameplay/UI constant lives in one
DebugPanel.define({...})schema. Game code readsT.group.keyat the point of use — never copied into a variable at init. - A tuning change edits schema defaults ONLY. Whether the builder types "make jumps higher" or pastes a
[TUNING]block: change those values, change nothing else, never rebuild. - The panel library ships with this skill as
debug-panel.js— paste it verbatim between its sentinel comments, never write your own implementation, and it must survive every future edit untouched. - Announce the panel on the first build, then teach with short tips. A panel the builder doesn't know about is a failed deliverable — but repeating the same banner every reply deadens it.
- Once read, this skill never turns off. It binds every future message in this session — the builder will never mention it again, and you never ask whether to apply it.
When this applies
- Creating a game or interactive toy (something with a game loop, player input, score, or win/lose). NOT plain pages, forms, or documents — skip this skill entirely for those.
- Adding or changing gameplay/UI features in an existing game.
- Tuning-type requests: "too fast/slow", "too big/small", "a bit more/less", "move it left/right/up/down", "can't hit it / my tap doesn't register", "hitbox", "feels floaty/heavy/off", "make it easier/harder", "change X from N to M", "don't rebuild, only fix this".
- Panel-addition requests: "add ○○ to the tuning panel" — the hint at the bottom of the panel teaches builders to ask exactly this. Register it via the PROMOTE two-step if it's not in the schema yet, and confirm in one line naming the group it landed in.
- Any message containing a
[TUNING]or[ERRORS]line — these come from the panel; handle them exactly per Protocol below.
Litmus test: if the correct fix is changing ≤3 constant values (number, position, size, color, duration), it is a tuning request → serve it through the schema, never with new inline literals. The litmus decides — trigger phrases only get you here. When the complaint could be a logic bug (especially right after you added the feature involved, e.g. "the boss doesn't take hits"), read the relevant code first. If the fix is code, make the smallest code fix with schema defaults untouched, and point the builder at the show hitboxes toggle and the Copy errors button.
Reply language: all builder-facing lines — confirmations, tips, announcements — are written in the builder's language. Keep 🔧/✅, the [TUNING]/[ERRORS] sentinels, and dotted key paths (player.speed) untranslated.
Persistence — once loaded, always on:
- This skill applies from the first game-related message and to every message after it, without being re-mentioned. Non-game messages in between do not unload it — when game work resumes, the rules still bind.
- Never ask the builder whether to add the panel or follow these rules, and never wait for a reminder. The builder chose this by giving you this repo once; that choice covers the whole session.
- Every new game, every edit, every feature, and every
[TUNING]/[ERRORS]paste in this session is governed by this skill — not just the game it was first applied to. - If your context no longer contains this skill (long session, summarization, a new agent taking over), re-read
SKILL.mdfrom this repo before touching game code. Tripwires that live in the builder's own repo and survive context loss: theTUNABLES CONTRACTcomment atopgame.js, thedebug-panel.jsheader, and the repo-rootAGENTS.mdyou write on the first build (see "Leave the contract in the game repo"). Seeing any of them means these rules are in force — honour them even if you cannot reach the full skill.
The schema: single source of truth
Every gameplay/UI constant a builder could plausibly ask to change lives in one DebugPanel.define call near the top of the game code:
const T = DebugPanel.define({
player: { _label: 'Player',
speed: { value: 220, min: 0, max: 600, label: 'Move speed' },
jumpVel: { value: 520, min: 100, max: 1200, label: 'Jump strength' },
hitW: { value: 28, min: 8, max: 80, label: 'Player hitbox width' } },
enemies: { _label: 'Enemies',
spawnMs: { value: 1800, min: 200, max: 6000, label: 'Time between enemies (ms, lower = harder)' } },
ui: { _label: 'Buttons',
shootX: { value: 24, min: 0, max: 400, cssVar: '--shoot-x', unit: 'px', label: 'Shoot button X' },
shootW: { value: 64, min: 40, max: 160, cssVar: '--shoot-w', unit: 'px', label: 'Shoot button width' },
shootH: { value: 64, min: 40, max: 160, cssVar: '--shoot-h', unit: 'px', label: 'Shoot button height' } },
});
Game code reads values live, at the point of use:
// WRONG — captured once at init; the panel slider will silently do nothing:
const speed = T.player.speed;
function update(dt) { player.x += speed * dt; }
// RIGHT — read at use time (destructure only INSIDE the loop body, never above it):
function update(dt) { player.x += T.player.speed * dt; }
Rules:
- Keys are protocol tokens. Schema keys and group keys are ALWAYS short English ASCII identifiers (
player.speed, never플레이어.속도) — they appear in[TUNING]dotted paths and must be stable across languages. All human-facing text lives inlabel(leaves) and_label(groups), in the builder's language. The group keyadvancedis recognized by the panel (renders collapsed) — never rename the key; localize only its_label. - NEVER copy a
Tvalue into a top-level const, a closure, or an object field you don't refresh. If an engine consumes a value once (physics gravity, materials, one-shot CSS), bind it withonChange(see recipes). If it only applies at generation time (grid size, level count), flag itrestart: trueand register a Restart button. - Timer trap:
setInterval(spawn, T.enemies.spawnMs)andsetTimeout(..., T.x)capture the value once — the slider goes permanently dead. Use a dt-accumulator instead (spawnT += dt * 1000; if (spawnT >= T.enemies.spawnMs) { spawnT = 0; spawn(); }) or a self-reschedulingsetTimeoutthat re-readsTon each schedule. - UI geometry is always tunable — position AND size, all four keys. Every on-screen control the game has — or gains later when you add a feature — gets
x,y(position) andw,h(width and height) in theuigroup the moment it exists (cssVar-bound for DOM elements; a singlescalemay replacew/honly when the control can only scale as one unit). Registering position without size is the most common mistake — "make the button bigger" is asked as often as "move it". A new button shipped with only gameplay values (damage, cooldown), or with x/y but no width/height, is an incomplete feature. - NEVER introduce a new numeric literal, px value, color, or ms duration into gameplay/UI logic. Exempt: 0, 1, -1, 2 as math identities, array indices, math constants (
Math.PI) — and constants a builder would never plausibly ask about (internal easing factors, z-offsets) may live as named consts in one clearly-marked// internal constantssection below the schema. When in doubt, put it inadvanced. - NEVER change existing schema defaults except through a tuning request or a
[TUNING]paste. - PROMOTE (two-step) — when a requested value is not in the schema yet: (1) add the key to the schema and replace every occurrence of that literal that means the same thing with
T.group.key(a size used in both draw and collision must not fork); (2) change the default. Typical diff ≈ 3 lines; duplicated-literal use sites are allowed on top — call them out. - One define. In a single-file game, always extend the one top
define; a second mergeddefine()is only for multi-file games where a feature module owns its constants. Merge is first-wins: a laterdefine()for an existing path is silently ignored (default, range, label, ANDonChangeall discarded) — to change anything about an existing key, edit the define that first declared it; never attachonChangevia a second define.
Tuning requests: routing and diff budget
Map complaints to schema keys (only after the litmus passes):
| Builder says | Change |
|---|---|
| too fast / too slow | speed, velocity, interval, duration keys |
| button too small / can't tap it | ui.* size keys (+ hitbox padding) |
| can't hit the enemy / unfair | hitbox w/h keys — and point them at the show hitboxes toggle |
| feels floaty / heavy | gravity, jump velocity |
| too hard / too easy | spawn rate, HP, timers |
| too quiet / loud | audio volume keys |
| move it left/right/up/down | ui.* x/y keys |
Diff budget (hard rule): a [TUNING] block with N values → at most N changed schema lines, plus the matching CSS var() fallback line(s) for any cssVar key. A typed tuning request → ≤3 changed lines for already-exposed keys, plus ≈3 lines per PROMOTEd key (the litmus caps a tuning request at 3 constants, so worst case ≈9 lines, all schema or use-site substitutions). If your diff is bigger, you are doing it wrong — revert and redo. Never regenerate the file for a tuning request.
Teach while applying (never refuse, never only-teach):
- A tweak is consecutive when the previous builder message was also a tweak-shaped request (any group); a
[TUNING]paste resets the count. - First tweak → apply it AND append one tip line naming the control by its display labels (never keys):
Tip: you can drag this live — 🔧 panel → {Player} → {Move speed}. - Second and later consecutive tweaks → lead with the control location, then the confirmation:
**{Move speed}** is live in your 🔧 panel ({Player} group) — drag it while playing for instant feel-checks. Applied: 220 → 285. - Stop nudging after two leads with no
[TUNING]paste in response — the builder has chosen chat; keep applying tweaks tip-free and mention the panel again only when a new feature ships. - When a builder describes broken behavior in prose and a console error is plausible, append one tip:
If an error badge showed up on the 🔧 button, tap Copy errors and paste it here.
Protocol: [TUNING] and [ERRORS] pastes
The panel's Copy changes button emits (header sentence is localized; the [TUNING] sentinel never changes):
[TUNING] Apply these as the new defaults. Edit ONLY these values inside DebugPanel.define — do not refactor, rebuild, or change any other code.
player.speed: 220 -> 285
ui.shootX: 24 -> 12
(2 changes from the in-game tuning panel)
When any user message contains a [TUNING] line:
- Locate the
DebugPanel.defineschema and set each listed dotted path'svalue:to the new value. Values may be numbers, booleans, strings, or#hexcolors — keep the type exactly. If a path appears more than once, apply the last occurrence. - If a shown old value doesn't match the current schema default, apply the new value anyway (the paste may predate your previous apply) — never stall to ask; append one parenthetical:
(note: player.speed's old value differed from your paste — saved the new value regardless). If the new value already equals the current default, say it was already applied. If a listed path is missing from the schema, skip it and name it. - For cssVar keys, update every CSS
var()fallback for that variable to the new default in the same diff, and note it (… + 1 CSS fallback synced). - Change zero other lines, and reply with one line:
✅ Applied 2 tuning changes as new defaults (player.speed 220→285, ui.shootX 24→12). Nothing else touched.
No summary, no suggestions, no refactor, no "improvements" to nearby code. If the message also contains other requests, apply the tuning edits exactly per this protocol first (still schema-only, still within budget), make the ✅ line the first line of your reply, then handle the rest normally.
The panel's Copy errors button emits:
[ERRORS] Fix ONLY this error with the smallest possible change. Keep my tuned values as they are.
TypeError: Cannot read properties of undefined (reading 'x') — at game.html:342 — seen 7×
When a message contains an [ERRORS] line: fix exactly that error with the smallest change, keep all schema defaults as they are, and confirm in one or two lines referencing the error message. Do not refactor or rebuild.
Files in this skill
2debug-visualization skill questions
How do I install the debug-visualization skill in Claude Code?
Run npx degit NEXPACE-Limited/msu-skills/plugins/game-tools/skills/debug-visualization ~/.claude/skills/debug-visualization. Claude Code loads skills from ~/.claude/skills (all projects) or .claude/skills (one project) and uses a skill when its description matches the task.
Which clients can use the debug-visualization skill?
Any client that reads the Agent Skills format: Claude Code, Codex, Gemini CLI and claude.ai (upload as a ZIP). Scripts in the skill run only where the client allows code execution.