Agent skills, an llms.txt API index, and the defects verifying them uncovered - #1620
Open
obiot wants to merge 8 commits into
Open
Agent skills, an llms.txt API index, and the defects verifying them uncovered#1620obiot wants to merge 8 commits into
obiot wants to merge 8 commits into
Conversation
…ncovered Ship 23 task-oriented skills at `packages/melonjs/skills/`, versioned with the engine and installable in Claude Code as a plugin. Each covers one subsystem and ends with a symptom-to-cause table, because melonJS's characteristic failure is silent rather than fatal: the engine warns once and degrades, so wrong output — not a stack trace — is what the user sees. `AGENTS.md` ships alongside them for agents following that convention (Codex, Cursor, Gemini CLI), to copy into a game's project root. Add `scripts/generate-llms-txt.ts`, chained onto `pnpm doc`, publishing an index of every exported symbol at melonjs.github.io/melonJS/llms.txt — the escape hatch for anything the skills do not cover. It reads the same TSDoc the reference pages render, so it cannot drift; marks deprecated entries, which are exactly what a model trained on older melonJS reaches for; and skips the 50 `String.prototype` pages typedoc emits for the `loader.nocache` string, which would otherwise present `loader.nocache.trimEnd` as melonJS API. Verifying the skills against the source found six code defects. Each is fixed with a test written to fail first: - Tiled: an object with no explicit geometry got a *triangular* collision shape — `(0,0), (w,0), (w,h)` omits the fourth vertex, so the lower-left half of every plain rectangle in a map was not solid. - Timer: `setInterval`'s `pauseable` argument was discarded by `pauseable === true || true`, so no repeating timer could survive a pause. `setTimeout` was unaffected (#1619). - Loader: the error path read `this.onError` from a module function, which has no `this` — a detached `preload` reported "Cannot read properties of undefined" instead of the real load failure. - Loader: `onload` / `onProgress` / `onError` are removed. Deprecated since 18.2.0, they were `let` bindings on a module namespace, so assigning them always threw; the documented migration path never worked, and the branch guarding `onProgress` was dead code. - Input: `preventDefault` is documented as a global option but is read-only for the same reason. `setPreventDefault()` is the working form. - Canvas: `setBlendMode("none")` resolves to `"normal"` explicitly rather than by fall-through — there is no `globalCompositeOperation` that disables blending for the drawn area alone. The same pass corrected the API reference against the code it documents: `Renderable#draw` told you to draw at `(0, 0)` when `preDraw` never translates to `this.pos`; the `body` example called `viewport.follow(this.pos, …)`, which throws; `Camera3d` documented a `roll` axis that does not exist; `Mesh` omitted eight constructor settings including `lit`; the `Asset` typedef advertised `"tmj"` / `"tsj"` types that throw; `Body#addShape`'s documentation had drifted onto a private helper; and 18 effect classes carried an unresolvable `@param` import path plus examples teaching `renderable.shader =`, deprecated since 19.2.0. Also: bump melonjs to 20.3.0 so the built `version` matches the unreleased line, guard the plugin manifest against drifting from it in `release.ts`, and give the root tsconfig `types: ["node"]` so `scripts/` type-checks at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Aa37KGXZcnVrbn1yG4j1N
Two fixes to the marketplace-facing blurb. The em dash was escaped as — — a Python json.dump artifact, not a choice. It parses identically, but nothing else in the repo is written that way. More importantly the wording led with "the pitfalls that make generated code fail silently". That is the honest reason the skills exist and it belongs in them, but as the first line someone reads it describes the engine as a minefield rather than saying what installing this gets you. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Aa37KGXZcnVrbn1yG4j1N
Its own JSDoc shows a rainbow-gradient example, so it is the obvious thing to reach for when a prompt asks for a trail — and under a Camera3d it draws a flat ribbon that does not recede with perspective. Names the two routes that do work in 3D: a world-space emitter, or a ribbon mesh with vertexColors. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Aa37KGXZcnVrbn1yG4j1N
"2.5D engine" undersells both ends: someone looking for a 2D platformer may not realise that is the engine's core, and nobody would guess there is a real 3D tier — perspective cameras, meshes, glTF scenes, instancing, 3D lights. It also matters for skill selection. The router's description is what gets matched against a task, so a prompt phrased purely in 2D or purely in 3D terms should hit it. Applied to both plugin manifests, the router skill and the shipped AGENTS.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Aa37KGXZcnVrbn1yG4j1N
Reviewed down to what a user acts on. The core-js removal and the two loader restructurings (moving the fetch helper to utils/, registering audio through a parser) are internal — no API changed, so they belong in the commit history rather than in release notes someone reads to decide whether to upgrade. `setPreventDefault` moved to Added, where a new export belongs. Two corrections on top of that review: the Howler sentence was missing an article, and it still said the vendoring removed "the last runtime dependency besides core-js". core-js is gone as of this same release and no longer mentioned anywhere in the file, so that clause left the reader thinking it remains. melonjs now declares no runtime dependencies at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Aa37KGXZcnVrbn1yG4j1N
The README and the website already state that the engine has no dependencies, so restating it as news is redundant — and it made the entry lead with a property rather than with the change. What a reader needs here is that the audio backend is in-tree now, and that the type declarations no longer point at a package they had to install themselves. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Aa37KGXZcnVrbn1yG4j1N
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Aa37KGXZcnVrbn1yG4j1N
CodeQL flagged `replace(/<[^>]+>/g, "")` as an incomplete sanitizer, and it is right about the shape: an unterminated `<script` never matches the pattern and survives into the output. Harmless here — the input is typedoc's own HTML and the output is a text file, never a DOM — but it is a new high-severity alert on a release, and the sound version is ten lines. Scanning from `<` to the next `>` cannot leave a tag behind, and an unterminated one takes the rest of the fragment with it. Verified against both shapes CodeQL cites, and the generated llms.txt is byte-identical. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Aa37KGXZcnVrbn1yG4j1N
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ships melonJS's guidance for AI coding assistants, and fixes the six code defects that verifying it against the source turned up.
Skills
23 task-oriented guides at
packages/melonjs/skills/, versioned with the engine so the guidance always matches the release innode_modules. Each covers one subsystem and ends with a symptom → cause table, because melonJS's characteristic failure is silent rather than fatal — the engine warns once and degrades, so what the user sees is wrong output, not a stack trace./plugin marketplace add melonjs/melonJS(manifests in.claude-plugin/,claude plugin validate --strictpasses)skills/AGENTS.mdships ready to copy into a game's project rootmelonjs/SKILL.mdis a router — an agent reads it, then the one or two guides it points at, not all 23llms.txtscripts/generate-llms-txt.tsruns after typedoc inpnpm doc, so the docs workflow publishes an index of every exported symbol at https://melonjs.github.io/melonJS/llms.txt. It is the escape hatch for anything the skills do not cover.It reads the same TSDoc the reference pages render, so it cannot drift from them. Two details that took iteration: deprecated entries are marked, since those are precisely what a model trained on older melonJS reaches for; and the 50
String.prototypepages typedoc emits for theloader.nocachestring are skipped, because indexing them would tell an agent thatloader.nocache.trimEndis part of the melonJS API. (Those pages are still in the published reference — a separate issue.)Six defects, each proven by a failing test first
bodyDef.shapes[0].contains(4, 28)→falsefor a 32×32 recttimer.setIntervaldiscarded itspauseableargumenttrueforfalse; never fired while paused —setTimeoutpassed the same testthis.onErrorfrom a module functionpreloadrejected withCannot read properties of undefined (reading 'onError')loader.onload/onProgress/onErrorunsettableTypeError— the documented callback API was unusableinput.preventDefaultunsettablesetBlendMode("none")resolved by fall-throughThe Tiled one is the most consequential:
(0,0), (w,0), (w,h)omits the fourth vertex, so the lower-left half of every plain rectangular object in every map was not solid. Walk into it from the left and you pass through.Two are removals rather than repairs.
loader.onload/onProgress/onErrorwereletbindings on an ES module namespace — assigning them always threw, so the migration path documented since 18.2.0 never worked for anyone, andloader.js'sonProgressbranch was dead code.input.preventDefaultwent the other way and gainedsetPreventDefault(), since it is a live option the engine reads rather than a deprecated one.API reference corrected against the code
The same verification pass found the docs disagreeing with the source in 30 places. The rule applied throughout: where JSDoc and code disagree, the code wins and the doc changes — except
timer.ts, where the code was the defect.Renderable#drawtold you to draw at(0, 0);preDrawnever translates tothis.posbody@examplecalledviewport.follow(this.pos, …), which throwsCamera3ddocumented arollaxis that does not existMeshomitted eight constructor settings, includinglit— the switch for the whole lit-mesh pathAssettypedef advertised"tmj"/"tsj"types that throw (extensions, not types)Body#addShape's documentation had drifted onto a private helper, leaving the public method undocumented@paramimport path, and 33 examples across 20 files taughtrenderable.shader =, deprecated since 19.2.0The wiki carried three of the same errors and is already fixed (
a24ab3e,6e168f7) — two of them were where the engine's own JSDoc got them from.Housekeeping
melonjs→ 20.3.0, so the builtversionexport, console header andplugin.registergate match the unreleased linerelease.tsnow aborts before tagging if.claude-plugin/plugin.jsonhas drifted from ittsconfig.jsongainstypes: ["node"]—scripts/had 8 pre-existing type errors because node built-ins were unresolved, invisible to CI sinceturbo test:typesonly runs inside packagesVerification
6431 tests passing(264 files, 0 failures) · eslint 0 errors · biome clean ·tscclean · typedoc 0 errors ·claude plugin validate --strictpasses ·npm packships all 23 skills plusAGENTS.mdCloses #1619
🤖 Generated with Claude Code
https://claude.ai/code/session_012Aa37KGXZcnVrbn1yG4j1N