Skip to content

Docs: stop publishing engine internals in the reference and in autocomplete - #1639

Merged
obiot merged 5 commits into
masterfrom
fix/doc-hygiene-internals
Sep 4, 2026
Merged

Docs: stop publishing engine internals in the reference and in autocomplete#1639
obiot merged 5 commits into
masterfrom
fix/doc-hygiene-internals

Conversation

@obiot

@obiot obiot commented Sep 3, 2026

Copy link
Copy Markdown
Member

Closes #1637.

The problem

Two leaks with the same symptom, and a member can hit either or both:

  • @ignore hides a member from the generated docs — but leaves it in the emitted .d.ts.
  • A member with no tag at all appears in both.

So the pass lifecycle, texture retirement, batcher plumbing and a long tail of one-shot warning flags were being offered to consumers as things to use. It also buries the genuinely useful API: the methods you want are lost among dozens you shouldn't touch.

scripts/strip-internal.ts already existed for exactly this — its own header names the case: "engine internals (pass lifecycle, texture retirement, …) would otherwise surface in consumers' autocomplete." It keys on @internal, and almost nothing carried that tag.

The fix, in two halves

Every @ignored declaration now also carries @internal. That is not a new judgement — it is the statement of intent the author already made, applied to the types as well as the docs. 1177 blocks.

The stripper also drops class members whose name begins with _. Tagging alone still left hundreds behind, because most internals were never tagged at all. The underscore prefix is this codebase's own convention for "not part of the API" and it is used consistently, so treating it as the declaration it already is covers the untagged ones and any added later — no tag needed on every one.

Deliberately limited to class members: a module-level _name is not emitted unless exported, and an exported one is a decision rather than an accident.

Result

master this branch
underscore-prefixed members in the published types 462 0
declared members in the published types 4747 3293

1454 declarations removed, no public API moved.

Two deliberate exemptions

An @ignored type that another emitted declaration imports cannot be stripped, or the published .d.ts is left with a dangling import — which breaks every consumer's type-check, not just the docs. ResolvedApplicationSettings and Fog3dState are both in that position: they keep @ignore and lose @internal, with a comment saying why so nobody re-adds it.

Both were found by type-checking the workspace plugins against the stripped output rather than by reading, which is the only reliable way to catch this class of breakage.

Verification

  • all five workspace plugins (spine, debug, tiled-inflate, matter-adapter, planck-adapter) type-check against the stripped declarations: 0 engine-type errors
  • the examples package likewise: 0
  • a spot-check that ~33 obviously-public members (draw, preload, setOptions, play, addChild, drawMesh, setFog, …) all survive
  • full suite unchanged: 6633 tests, lint and types clean

Note on scope

This is mechanical and large (205 files) but behaviour-free: no runtime code changed except the build script. The diff is almost entirely one added @internal line per existing @ignore block.

…mplete

Two leaks with the same symptom. `@ignore` hides a member from the generated
documentation but leaves it in the emitted `.d.ts`; a member with no tag at all
appears in both. So the pass lifecycle, texture retirement, batcher plumbing
and a long tail of one-shot warning flags were offered to consumers as things
to use, and the genuinely public surface was buried among them.

`strip-internal.ts` already existed for exactly this, keyed on `@internal` —
but almost nothing carried that tag. Every `@ignore`d declaration now carries
it too, which is a statement of intent the author had already made.

That still left the members nobody tagged, so the stripper additionally drops
class members whose name begins with `_`. The underscore prefix is this
codebase's own convention for "not part of the API" and it is used
consistently; treating it as the declaration it already is covers the untagged
ones and any added later, without needing a tag on every one. It is limited to
class members: a module-level `_name` is not emitted unless exported, and an
exported one is a decision rather than an accident.

1454 declarations left the published types, 462 of them underscore-prefixed.

Two types are deliberately exempt, and the reason is worth recording: an
`@ignore`d type that another emitted declaration imports cannot be stripped, or
the published `.d.ts` is left with a dangling import. `ResolvedApplicationSettings`
and `Fog3dState` are both in that position, so they keep their `@ignore` and
lose the `@internal`.

Verified no public API moved: all five workspace plugins and the examples
type-check against the stripped declarations with zero errors, and the full
suite is unchanged.

Closes #1637

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Aa37KGXZcnVrbn1yG4j1N
Copilot AI lite review requested due to automatic review settings September 3, 2026 08:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The underscore stripping implementation in strip-internal.ts currently applies beyond class members (interfaces/type literals too), which can remove more from the published .d.ts than the PR states/intends.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR reduces accidental exposure of engine internals in both generated API reference docs and in published TypeScript declaration output by consistently marking non-public surfaces as internal and enhancing the declaration post-processing step to drop underscore-prefixed class members.

Changes:

  • Add @internal alongside existing @ignore tags across many internal members so they are stripped from published .d.ts output.
  • Extend packages/melonjs/scripts/strip-internal.ts to also remove underscore-prefixed members (intended as an internal-by-convention signal).
  • Document the change in packages/melonjs/CHANGELOG.md.
File summaries
File Description
packages/melonjs/src/video/webgpu/webgpu_renderer.js Add @internal to ignored internal members/methods
packages/melonjs/src/video/webgpu/texture/store.js Add @internal to ignored internal APIs
packages/melonjs/src/video/webgpu/texture/frametexture.js Add @internal to ignored internal APIs
packages/melonjs/src/video/webgpu/texture/compressed.js Add @internal to ignored internal exports
packages/melonjs/src/video/webgpu/shaders/mesh-instanced.js Add @internal to ignored internal exports
packages/melonjs/src/video/webgpu/renderers/tmxlayer/orthogonal.js Add @internal to ignored internal APIs/constants
packages/melonjs/src/video/webgpu/pipeline/cache.js Add @internal to ignored internal APIs/constants
packages/melonjs/src/video/webgpu/pipeline/bindgroups.js Add @internal to ignored internal constants
packages/melonjs/src/video/webgpu/effect_binding.js Add @internal to ignored internal helpers/APIs
packages/melonjs/src/video/webgpu/buffer/uniformring.js Add @internal to ignored internal APIs
packages/melonjs/src/video/webgpu/buffer/retained_geometry.js Add @internal to ignored internal APIs
packages/melonjs/src/video/webgpu/buffer/instance_buffer.js Add @internal to ignored internal APIs
packages/melonjs/src/video/webgpu/buffer/arena.js Add @internal to ignored internal APIs
packages/melonjs/src/video/webgpu/batchers/quad_batcher.js Add @internal to ignored internal members/APIs
packages/melonjs/src/video/webgpu/batchers/primitive_batcher.js Add @internal to ignored internal members
packages/melonjs/src/video/webgpu/batchers/lit_quad_batcher.js Add @internal to ignored internal overrides
packages/melonjs/src/video/webgpu/batchers/lit_mesh_batcher.js Add @internal to ignored internal overrides
packages/melonjs/src/video/webgl/utils/vertexformat.js Add @internal to ignored internal utilities
packages/melonjs/src/video/webgl/utils/uniforms.js Add @internal to ignored internal utilities
packages/melonjs/src/video/webgl/utils/topology.js Add @internal to ignored internal utilities/constants
packages/melonjs/src/video/webgl/utils/string.js Add @internal to ignored internal utilities
packages/melonjs/src/video/webgl/utils/samplercache.js Add @internal to ignored internal class/APIs
packages/melonjs/src/video/webgl/utils/program.js Add @internal to ignored internal shader helpers
packages/melonjs/src/video/webgl/utils/precision.js Add @internal to ignored internal shader helpers
packages/melonjs/src/video/webgl/utils/maxtextures.js Add @internal to ignored internal constants/helpers
packages/melonjs/src/video/webgl/utils/attributes.js Add @internal to ignored internal utilities
packages/melonjs/src/video/webgl/texture/store.js Add @internal to ignored internal APIs
packages/melonjs/src/video/webgl/shaders/multitexture.js Add @internal to ignored internal shader builder
packages/melonjs/src/video/webgl/shaders/multitexture-lit.js Add @internal to ignored internal shader builders
packages/melonjs/src/video/webgl/renderers/tmxlayer/orthogonal.js Add @internal to ignored internal renderer
packages/melonjs/src/video/webgl/lighting/std140.ts Add @internal to ignored internal constants/helpers
packages/melonjs/src/video/webgl/lighting/pack3d.ts Add @internal to ignored internal types/helpers
packages/melonjs/src/video/webgl/glshader.js Add @internal to ignored internal method
packages/melonjs/src/video/webgl/buffer/vertexstate.js Add @internal to ignored internal helpers/methods
packages/melonjs/src/video/webgl/buffer/uniformblock.js Add @internal to ignored internal APIs
packages/melonjs/src/video/webgl/buffer/retained_geometry.js Add @internal to ignored internal APIs/helpers
packages/melonjs/src/video/webgl/buffer/instance_buffer.js Add @internal to ignored internal class
packages/melonjs/src/video/webgl/buffer/index.js Add @internal to ignored internal class
packages/melonjs/src/video/webgl/batchers/quad_batcher.js Add @internal to ignored internal batcher APIs
packages/melonjs/src/video/webgl/batchers/primitive_batcher.js Add @internal to ignored internal batcher APIs
packages/melonjs/src/video/webgl/batchers/material_batcher.js Add @internal to ignored internal batcher APIs
packages/melonjs/src/video/webgl/batchers/lit_mesh_batcher.js Add @internal to ignored internal batcher methods
packages/melonjs/src/video/webgl/batchers/batcher.js Add @internal to ignored internal batcher methods/fields
packages/melonjs/src/video/utils/autodetect.js Add @internal to ignored internal helper
packages/melonjs/src/video/texture/texture2d.ts Add @internal to ignored internal brand/types
packages/melonjs/src/video/texture/resource.js Add @internal to ignored internal APIs
packages/melonjs/src/video/texture/parser/texturepacker.js Add @internal to ignored internal parser export
packages/melonjs/src/video/texture/parser/spritesheet.js Add @internal to ignored internal parser export
packages/melonjs/src/video/texture/parser/aseprite.js Add @internal to ignored internal parser export
packages/melonjs/src/video/texture/noise_texture2d.js Add @internal to ignored internal members/helpers
packages/melonjs/src/video/texture/frametexture.js Add @internal to ignored internal classes
packages/melonjs/src/video/texture/atlas.js Add @internal to ignored internal helpers/members
packages/melonjs/src/video/rendertarget/webgpurendertarget.js Add @internal to ignored internal method
packages/melonjs/src/video/rendertarget/webglrendertarget.js Add @internal to ignored internal helpers/methods
packages/melonjs/src/video/rendertarget/render_target_pool.js Add @internal to ignored internal class
packages/melonjs/src/video/rendertarget/canvasrendertarget.js Add @internal to ignored internal methods
packages/melonjs/src/video/renderstate.js Add @internal to ignored internal members/methods
packages/melonjs/src/video/renderer.js Add @internal to ignored internal members/methods
packages/melonjs/src/video/gradient.js Add @internal to ignored internal constants/members
packages/melonjs/src/video/gpu/vertexformat.ts Add @internal to ignored internal types/constants
packages/melonjs/src/video/gpu/topology.ts Add @internal to ignored internal constants
packages/melonjs/src/video/gpu/texturestore.js Add @internal to ignored internal APIs
packages/melonjs/src/video/gpu/textureslots.js Add @internal to ignored internal APIs
packages/melonjs/src/video/gpu/quadcorners.ts Add @internal to ignored internal helpers
packages/melonjs/src/video/gpu/primitives.ts Add @internal to ignored internal helpers
packages/melonjs/src/video/gpu/meshvertex.ts Add @internal to ignored internal helpers
packages/melonjs/src/video/gpu/meshchunk.ts Add @internal to ignored internal helpers
packages/melonjs/src/video/gpu/instancerecord.ts Add @internal to ignored internal types/helpers/constants
packages/melonjs/src/video/gpu/batcher.js Add @internal to ignored internal constant
packages/melonjs/src/video/effects/wgsl/scaffold.js Add @internal to ignored internal helpers
packages/melonjs/src/video/effects/wgsl/parse.js Add @internal to ignored internal helpers
packages/melonjs/src/video/effects/wgsl/layout.js Add @internal to ignored internal helpers/constants
packages/melonjs/src/video/effects/wgsl_realization.js Add @internal to ignored internal class
packages/melonjs/src/video/effects/glsl_realization.js Add @internal to ignored internal helpers
packages/melonjs/src/video/effects/colorMatrix.js Add @internal to ignored internal members/methods
packages/melonjs/src/video/effects/blendEffect.js Add @internal to ignored internal class/method
packages/melonjs/src/video/canvas/canvas_renderer.js Add @internal to ignored internal setters
packages/melonjs/src/video/canvas_factory.js Add @internal to ignored internal helper
packages/melonjs/src/video/buffer/vertex.js Add @internal to ignored internal APIs
packages/melonjs/src/video/buffer/index.js Add @internal to ignored internal class
packages/melonjs/src/video/blendmodes.js Add @internal to ignored internal constants/helpers
packages/melonjs/src/utils/utils.ts Add @internal to ignored internal helpers
packages/melonjs/src/utils/fetchdata.js Add @internal to ignored internal helpers
packages/melonjs/src/utils/decode.ts Add @internal to ignored internal helper
packages/melonjs/src/utils/array-multimap.js Add @internal to ignored internal class
packages/melonjs/src/tweens/tween.ts Add @internal to ignored internal types/methods
packages/melonjs/src/system/timer.ts Add @internal to ignored internal methods
packages/melonjs/src/system/save.ts Add @internal to ignored internal helper
packages/melonjs/src/system/pool.ts Add @internal to ignored internal registry APIs
packages/melonjs/src/system/legacy_pool.js Add @internal to ignored internal hooks
packages/melonjs/src/system/dom.ts Add @internal to ignored internal helper
packages/melonjs/src/system/device.ts Add @internal to ignored internal helpers
packages/melonjs/src/state/state.ts Add @internal to ignored internal runloop helpers
packages/melonjs/src/state/stage.ts Add @internal to ignored internal stage APIs
packages/melonjs/src/renderable/ui/uispriteelement.ts Add @internal to ignored internal event handlers
packages/melonjs/src/renderable/ui/uibaseelement.ts Add @internal to ignored internal event handlers
packages/melonjs/src/renderable/trigger.js Add @internal to ignored internal helper
packages/melonjs/src/renderable/trail.js Add @internal to ignored internal members/methods
packages/melonjs/src/renderable/text/textstyle.js Add @internal to ignored internal helper
packages/melonjs/src/renderable/text/text.js Add @internal to ignored internal methods/members
packages/melonjs/src/renderable/text/glyph.ts Add @internal to ignored internal class/members
packages/melonjs/src/renderable/text/bitmaptextdata.ts Add @internal to ignored internal helpers/methods
packages/melonjs/src/renderable/text/bitmaptext.js Add @internal to ignored internal members/methods
packages/melonjs/src/renderable/sprite.js Add @internal to ignored internal members/methods
packages/melonjs/src/renderable/renderable.js Add @internal to ignored internal members/methods
packages/melonjs/src/renderable/nineslicesprite.js Add @internal to ignored internal overrides
packages/melonjs/src/renderable/imagelayer.js Add @internal to ignored internal methods
packages/melonjs/src/renderable/groundshadow.js Add @internal to ignored internal helpers/constants
packages/melonjs/src/renderable/frameAnimation.js Add @internal to ignored internal members/helpers
packages/melonjs/src/renderable/entity/entity.js Add @internal to ignored internal members/methods
packages/melonjs/src/renderable/dragndrop.js Add @internal to ignored internal destructor
packages/melonjs/src/renderable/draggable.js Add @internal to ignored internal destructor
packages/melonjs/src/renderable/colorlayer.js Add @internal to ignored internal destructor
packages/melonjs/src/renderable/animation.ts Add @internal to ignored internal option field
packages/melonjs/src/renderable/anchorPoint.ts Add @internal to ignored internal types/helpers
packages/melonjs/src/polyfill/roundrect.ts Add @internal to ignored internal helpers
packages/melonjs/src/polyfill/ellipse.ts Add @internal to ignored internal helper
packages/melonjs/src/physics/world.js Add @internal to ignored internal constants/method
packages/melonjs/src/physics/builtin/sat3d.js Add @internal to ignored internal collision helpers
packages/melonjs/src/physics/builtin/body.js Add @internal to ignored internal members/helpers
packages/melonjs/src/physics/broadphase/quadtree.ts Add @internal to ignored internal helpers/types
packages/melonjs/src/physics/broadphase/broadphase.ts Add @internal to ignored internal interface field
packages/melonjs/src/particles/particle.ts Add @internal to ignored internal helpers/overrides
packages/melonjs/src/math/vertex.ts Add @internal to ignored internal helpers
packages/melonjs/src/math/vector2d.ts Add @internal to ignored internal method
packages/melonjs/src/loader/parsers/video.js Add @internal to ignored internal parser API
packages/melonjs/src/loader/parsers/tmx.js Add @internal to ignored internal parser helpers
packages/melonjs/src/loader/parsers/shader.js Add @internal to ignored internal shader loader APIs
packages/melonjs/src/loader/parsers/script.js Add @internal to ignored internal parser API
packages/melonjs/src/loader/parsers/pbr.ts Add @internal to ignored internal parser types/constants/helpers
packages/melonjs/src/loader/parsers/obj.js Add @internal to ignored internal parser helpers/APIs
packages/melonjs/src/loader/parsers/mtl.js Add @internal to ignored internal parser APIs
packages/melonjs/src/loader/parsers/json.js Add @internal to ignored internal parser API
packages/melonjs/src/loader/parsers/image.js Add @internal to ignored internal loader helpers
packages/melonjs/src/loader/parsers/fontface.js Add @internal to ignored internal parser API
packages/melonjs/src/loader/parsers/compressed_textures/parsePVR.js Add @internal to ignored internal parser API
packages/melonjs/src/loader/parsers/compressed_textures/parsePKM.js Add @internal to ignored internal parser API
packages/melonjs/src/loader/parsers/compressed_textures/parseKTX2.js Add @internal to ignored internal parser API
packages/melonjs/src/loader/parsers/compressed_textures/parseKTX.js Add @internal to ignored internal parser API
packages/melonjs/src/loader/parsers/compressed_textures/parseDDS.js Add @internal to ignored internal parser API
packages/melonjs/src/loader/parsers/compressed_textures/compressed_image.js Add @internal to ignored internal helper
packages/melonjs/src/loader/parsers/binary.js Add @internal to ignored internal parser API
packages/melonjs/src/loader/parsers/audio.js Add @internal to ignored internal audio loader APIs
packages/melonjs/src/loader/parsers/aseprite.js Add @internal to ignored internal parser helpers
packages/melonjs/src/loader/loadingscreen.js Add @internal to ignored internal loading-screen classes/members
packages/melonjs/src/loader/loader.js Add @internal to ignored internal loader internals
packages/melonjs/src/lighting/light3d.ts Add @internal to ignored internal lifecycle hooks
packages/melonjs/src/lighting/light2d.ts Add @internal to ignored internal members/lifecycle hooks
packages/melonjs/src/level/tiled/TMXUtils.js Add @internal to ignored internal utilities
packages/melonjs/src/level/tiled/TMXTileset.js Add @internal to ignored internal members/methods
packages/melonjs/src/level/tiled/TMXTileMap.js Add @internal to ignored internal helpers/members
packages/melonjs/src/level/tiled/TMXTile.js Add @internal to ignored internal helpers/methods
packages/melonjs/src/level/tiled/TMXObjectFactory.js Add @internal to ignored internal factory internals
packages/melonjs/src/level/tiled/TMXObject.js Add @internal to ignored internal helpers/methods
packages/melonjs/src/level/tiled/TMXLayer.js Add @internal to ignored internal helpers/members
packages/melonjs/src/level/tiled/TMXGroup.js Add @internal to ignored internal class/methods
packages/melonjs/src/level/tiled/renderer/TMXStaggeredRenderer.js Add @internal to ignored internal renderer methods
packages/melonjs/src/level/tiled/renderer/TMXOrthogonalRenderer.js Add @internal to ignored internal renderer methods
packages/melonjs/src/level/tiled/renderer/TMXObliqueRenderer.js Add @internal to ignored internal renderer methods
packages/melonjs/src/level/tiled/renderer/TMXIsometricRenderer.js Add @internal to ignored internal renderer methods
packages/melonjs/src/level/tiled/renderer/TMXHexagonalRenderer.js Add @internal to ignored internal renderer methods
packages/melonjs/src/level/tiled/renderer/autodetect.js Add @internal to ignored internal autodetect helper
packages/melonjs/src/level/tiled/factories/tile.js Add @internal to ignored internal factory
packages/melonjs/src/level/tiled/factories/text.js Add @internal to ignored internal factory
packages/melonjs/src/level/tiled/factories/shape.js Add @internal to ignored internal factory
packages/melonjs/src/level/level.js Add @internal to ignored internal level loader helpers
packages/melonjs/src/level/gltf/GLTFScene.js Add @internal to ignored internal helpers
packages/melonjs/src/level/gltf/gltf_sampler.js Add @internal to ignored internal helpers
packages/melonjs/src/input/pointerevent.ts Add @internal to ignored internal event plumbing
packages/melonjs/src/input/pointer.ts Add @internal to ignored internal helpers/ctor
packages/melonjs/src/input/gamepad.ts Add @internal to ignored internal helpers
packages/melonjs/src/geometries/toarccanvas.ts Add @internal to ignored internal helpers
packages/melonjs/src/geometries/sphere.ts Add @internal to ignored internal members/helpers
packages/melonjs/src/geometries/roundrect.ts Add @internal to ignored internal helper
packages/melonjs/src/geometries/polygon.ts Add @internal to ignored internal members
packages/melonjs/src/geometries/path2d.ts Add @internal to ignored internal members/helpers
packages/melonjs/src/geometries/box3d.ts Add @internal to ignored internal constants/members/helpers
packages/melonjs/src/camera/fog.ts Add explanatory note for @ignored-but-emitted type
packages/melonjs/src/camera/effects/mask_effect.ts Add @internal to ignored internal member
packages/melonjs/src/camera/effects/fade_effect.ts Add @internal to ignored internal member
packages/melonjs/src/audio/state.ts Add @internal to ignored internal state/helpers
packages/melonjs/src/audio/procedural.ts Add @internal to ignored internal helpers
packages/melonjs/src/application/settings.ts Add explanatory note for @ignored-but-emitted type
packages/melonjs/src/application/application.ts Add @internal to ignored internal helper/methods
packages/melonjs/scripts/strip-internal.ts Strip underscore-prefixed members in emitted .d.ts
packages/melonjs/CHANGELOG.md Document the user-visible impact
Review details
  • Files reviewed: 205/205 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/melonjs/scripts/strip-internal.ts
…nted

The doc comment said class members only, but the implementation also matched
`PropertySignature` and `MethodSignature` — interface members. An exported
interface's `_field` is part of a contract someone may implement, so removing
it changes that contract rather than hiding an implementation detail.

`SpatialAudioState._pos`, `SpatialSoundState._pannerAttr` and nine siblings
are real cases in this codebase.

Raised by Copilot on #1639.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Aa37KGXZcnVrbn1yG4j1N
Copilot AI review requested due to automatic review settings September 3, 2026 09:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The new underscore prefilter/selector logic in scripts/strip-internal.ts can miss (or unintentionally match) members due to overly narrow hinting and PrivateIdentifier handling, risking incomplete or incorrect stripping.

Review details

Suppressed comments (2)

Previously missed (1) — in code that hasn't changed since the last review.

packages/melonjs/scripts/strip-internal.ts:36

  • UNDERSCORE_HINT is used to skip parsing .d.ts files, but the current pattern only matches members whose declaration line starts directly with _ (optionally preceded by readonly). In .d.ts output, underscore-prefixed class members can be preceded by modifiers like static, public, protected, or private, which would cause the file to be skipped and those underscore members to remain unstripped.

packages/melonjs/scripts/strip-internal.ts:70

  • isUnderscoreMember currently treats ts.PrivateIdentifier names as underscore-prefixed members. A private field like #_foo does not actually start with _ at the source level and is already non-public; including PrivateIdentifier here is inconsistent with the stated rule and could strip unintended declarations.
	const name = node.name;
	return (
		(ts.isIdentifier(name) || ts.isPrivateIdentifier(name)) &&
		name.text.startsWith("_")
	);
  • Files reviewed: 205/205 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@obiot

obiot commented Sep 3, 2026

Copy link
Copy Markdown
Member Author

Review fix

d5187741a — Copilot was right. isUnderscoreMember documented "class members only" but the implementation also matched PropertySignature / MethodSignature, i.e. interface members. An exported interface's _field is part of a contract someone may implement, so removing it changes that contract rather than hiding an implementation detail. SpatialAudioState._pos, SpatialSoundState._pannerAttr and nine siblings are real cases here. The check is now limited to class members, matching what the comment claims.

Scope correction — this PR fixes one of the two leaks, not both

Worth stating plainly, because #1637's screenshots show the other one.

TypeDoc runs on source (typedoc src/index.ts), not on the emitted declarations — and it already honours @ignore by default. So adding @internal alongside every @ignore changes nothing in the generated reference. What it changes is the published .d.ts, which is a real and separate problem: those members were absent from the docs but present in consumers' autocomplete.

The members in the issue's screenshots — _advancedBlendBusy, _effectPassDepth, lightUniformsScratch, savedBlendMode, setBatcher, blitEffect — carry no doc tag at all, so they leak into both. This PR removes them from the types; they remain in the reference.

before after
underscore members in the published .d.ts 462 0
declared members in the published .d.ts 4747 3293
underscore members in the generated reference 36 36

I attempted the reference half in the same branch and backed it out. The untagged members are mostly lazily assigned (this._x = … inside a method) rather than declared, so tagging them mechanically produces duplicated doc comments on fields that already have one — which TypeDoc reports as "multiple declarations with a comment" and resolves arbitrarily. My passes doubled the warning count (311 → 494) and in one case duplicated a description line inside an interface body. That wants a considered approach, not a regex.

Suggest merging this for the types fix and tracking the reference half separately — #1637 can stay open for it, or I can split it into its own issue with the above written up.

Still green

6633 tests, lint and types clean, all five workspace plugins and the examples type-check against the stripped declarations with zero errors.

obiot and others added 3 commits September 4, 2026 09:46
…as warning about

The earlier pass tagged `@internal` alongside every `@ignore`, which fixed the
published `.d.ts` — but not the reference. TypeDoc reads source and already
honours `@ignore`, so the members it was documenting were the ones carrying no
tag at all: 89 underscore-prefixed properties and methods, including the ones
the issue's screenshots pointed at.

They are tagged where they are declared, which for most of them is a lazy
`this._x =` assignment rather than a class field. Three shapes needed their own
handling: module-level statics (`Renderer._whitePixel = null`), assignments
nested inside method bodies, and plain underscore methods. Same treatment per
CLASS rather than per name, since `_bounds` exists on Ellipse, Polygon and Rect
independently.

The build was also emitting 311 warnings, and three groups of those were real
defects rather than noise:

Thirteen links on the docs landing page were written as relative HTML paths
(`[Camera3d](classes/Camera3d.html)`), which TypeDoc neither copies nor
rewrites — dead links on the first page a reader sees. They are `{@link}` now.

Seventy-eight `@param` blocks documented parameters their signature did not
declare, so TypeDoc dropped the descriptions entirely: abstract stubs written
as `drawTile()` with four documented arguments, `onCollision(_response,
_other)` documented as `response`/`other`, and a handful documenting arguments
that had been removed. The stubs take their parameters (with the
eslint-disable this codebase already uses for the same case), and the stale
lines are gone.

Seventy legacy JSDoc tags — `@memberof`, `@name`, `@classdesc`, `@constant` —
left from the previous toolchain, ignored by TypeDoc with a warning apiece.

Down to 156 warnings. The remaining `@param` ones are TypeScript overloads and
nested option objects, both of which want a decision per method rather than a
pattern.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Aa37KGXZcnVrbn1yG4j1N
… skills

The docs landing page said nothing about the three things on it meant for
assistants as much as for people: the `llms.txt` index, the new Copy page
control, and the shipped skills. It does now.

The README's agent section led with Claude Code and lumped everything else into
a parenthesis, and never mentioned Copilot at all. One command covers all of
them — `npx skills add` resolves the repo subdirectory and writes each agent's
own convention, so the per-assistant copy steps are gone.

Verified against this repository: 23 skills installed, non-interactively when
run by an agent. It installs from `master`; the copy matching the exact release
you are running still ships in the package.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Aa37KGXZcnVrbn1yG4j1N
The generated reference looked like every other project using the same theme.
It now carries the engine's own: the logo beside the wordmark, a palette
sampled from that logo rather than invented (#6ba831 is the ring, #d1655b the
dot, #202020 the ink — the value the README and the engine's default background
already use), and the favicon. The header links out to the site, the wiki, the
repository and Discord.

A **Copy page** control hands the page to an assistant. It lifts the page's own
content into Markdown with the canonical URL attached and copies it, or opens
it in a chat — useful for asking about one class without a model fetching half
the reference.

TypeDoc's `navigationLinks` is a map and cannot be passed on the command line,
so the configuration moves to `typedoc.json`. That also takes a 400-character
`doc` script down to `typedoc`.

The root ignore rule was a bare `docs/`, which matches a directory of that name
at any depth — so `scripts/docs/` would have been silently untracked, leaving
`typedoc.json` pointing at a stylesheet nobody else has. It is anchored to the
generated output now.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Aa37KGXZcnVrbn1yG4j1N
Copilot AI review requested due to automatic review settings September 4, 2026 01:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The updated declaration stripper has a correctness risk in its underscore prefilter and the docs script mixes pnpm with npm run, both of which should be addressed before merging.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 230/231 changed files
  • Comments generated: 2
  • Review effort level: Lite

Comment on lines +35 to +37
/** cheap pre-filter for the underscore rule below */
const UNDERSCORE_HINT = /^\s*(readonly\s+)?_[A-Za-z0-9_]+\s*[?:(<]/m;

Comment on lines 78 to +81
"dist": "pnpm clean && pnpm lint && pnpm vitest run && pnpm build && pnpm doc && cp ../../README.md .",
"dist:publish": "pnpm clean && pnpm lint && pnpm build && pnpm doc && cp ../../README.md .",
"doc": "tsx scripts/check-doc-readme.ts && typedoc src/index.ts --tsconfig tsconfig.build.json --readme ../../DOC_README.md --hideGenerator --name 'melonJS' --navigation.includeCategories true --categorizeByGroup false && tsx scripts/generate-llms-txt.ts",
"doc:watch": "typedoc src/index.ts --tsconfig tsconfig.build.json --readme ../../DOC_README.md --hideGenerator --name 'melonJS' --navigation.includeCategories true --categorizeByGroup false --watch --skipErrorChecking --preserveWatchOutput --logLevel Error",
"doc": "tsx scripts/check-doc-readme.ts && npm run doc:css && typedoc && tsx scripts/generate-llms-txt.ts",
"doc:watch": "typedoc --watch --skipErrorChecking --preserveWatchOutput --logLevel Error",
@obiot
obiot merged commit 0dbcef0 into master Sep 4, 2026
7 checks passed
@obiot
obiot deleted the fix/doc-hygiene-internals branch September 4, 2026 01:53
obiot added a commit that referenced this pull request Sep 4, 2026
…ugh pnpm (#1640)

The pre-filter deciding whether a `.d.ts` is worth parsing only matched an
underscore member written bare or behind `readonly`. A file whose underscore
members all carry a modifier — `private _secret`, `protected _hidden()`,
`static _shared` — failed that test and was skipped outright, so those members
survived into the published types. Silent, because the file was never parsed
rather than parsed and passed over.

Nothing leaked: no emitted declaration currently uses those modifiers on an
underscore member, so the hole was latent. It would open the moment someone
wrote one in TypeScript source. Verified both ways against a probe declaration
carrying only modified members and no `@internal` — the old pattern skipped the
file, the new one parses it.

`doc` also shelled out to `npm run doc:css` while every other script in the
package uses pnpm, which can resolve differently in a workspace install.

Raised by Copilot on #1639.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Docs: engine internals are published in the API reference and in consumers' autocomplete

2 participants