diff --git a/.gitignore b/.gitignore
index dbec28ae7d..10ec483067 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,5 +18,6 @@ node_modules/
dist/*
!.placeholder
package-lock.json
-docs/
+# the generated API reference, not every directory named `docs`
+/packages/melonjs/docs/
.turbo
diff --git a/DOC_README.md b/DOC_README.md
index 43d912c622..93f6b3f162 100644
--- a/DOC_README.md
+++ b/DOC_README.md
@@ -46,15 +46,15 @@ loader.preload([{ name: "player", type: "image", src: "player.png" }], () => {
| Feature | Description |
|---------|-------------|
| **Rendering** | WebGPU, WebGL 2 and Canvas 2D with automatic fallback — the same feature set on every backend |
-| **3D** | Perspective [Camera3d](classes/Camera3d.html), mesh instancing, ground shadows, distance fog, point and spot lights, glTF/GLB and OBJ/MTL loading |
+| **3D** | Perspective {@link Camera3d | Camera3d}, mesh instancing, ground shadows, distance fog, point and spot lights, glTF/GLB and OBJ/MTL loading |
| **Tiled Maps** | First-class [Tiled](https://www.mapeditor.org/) map editor support (TMX/JSON), with GPU-accelerated tile rendering for orthogonal maps |
| **Sprites** | Texture atlas, animation, TexturePacker & Aseprite support |
-| **Physics** | Built-in SAT collision with gravity and friction, shape-level collision events, and a [PhysicsAdapter](interfaces/PhysicsAdapter.html) interface for Box2D (planck) or Matter.js |
+| **Physics** | Built-in SAT collision with gravity and friction, shape-level collision events, and a {@link PhysicsAdapter | PhysicsAdapter} interface for Box2D (planck) or Matter.js |
| **Audio** | Web Audio API with format fallback, plus procedural tone and noise generation |
| **Input** | Keyboard, mouse, touch, gamepad |
-| **Particles** | Configurable [ParticleEmitter](classes/ParticleEmitter.html), with a reference space so particles can be measured from the emitter, the world, or any container |
+| **Particles** | Configurable {@link ParticleEmitter | ParticleEmitter}, with a reference space so particles can be measured from the emitter, the world, or any container |
| **Effects** | All thirteen CSS blend modes on every renderer, tinting, masking, and camera post-processing chains |
-| **Custom Shaders** | Per-sprite [ShaderEffect](classes/ShaderEffect.html) carrying both GLSL and WGSL, so one effect runs on either GPU backend |
+| **Custom Shaders** | Per-sprite {@link ShaderEffect | ShaderEffect} carrying both GLSL and WGSL, so one effect runs on either GPU backend |
| **UI** | Built-in UI components (buttons, text input, containers) |
## Common Tasks
@@ -67,7 +67,7 @@ import { level } from "melonjs";
// load a level by name (must be preloaded first)
level.load("myLevel");
```
-See: [`level`](functions/level.load.html), [`TMXTileMap`](classes/TMXTileMap.html)
+See: {@link level.load | level}, {@link TMXTileMap | TMXTileMap}
#### Create a sprite with animations
Create a sprite from a texture atlas (e.g. exported from TexturePacker or Aseprite) and define animation sequences from named frames.
@@ -82,7 +82,7 @@ const player = new Sprite(100, 100,
atlas.getAnimationSettings(["walk01.png", "walk02.png", "walk03.png"])
);
```
-See: [`Sprite`](classes/Sprite.html), [`TextureAtlas`](classes/TextureAtlas.html)
+See: {@link Sprite | Sprite}, {@link TextureAtlas | TextureAtlas}
#### Handle keyboard and gamepad input
Bind physical keys or gamepad buttons to named actions, then check those actions in your game logic.
@@ -97,7 +97,7 @@ if (input.isKeyPressed("jump")) {
// make the player jump
}
```
-See: [`input`](modules/input.html)
+See: {@link input | input}
#### Add physics and collision to a game object
Attach a physics body with a collision shape to any renderable. The engine handles gravity, velocity, friction, and collision detection automatically.
@@ -114,7 +114,7 @@ this.body.collisionType = collision.types.PLAYER_OBJECT;
this.body.setMaxVelocity(3, 15);
this.body.setFriction(0.4, 0);
```
-See: [`Body`](classes/Body.html), [`collision`](modules/collision.html)
+See: {@link Body | Body}, {@link collision | collision}
#### Apply a custom shader effect to a sprite
Apply a per-sprite fragment shader using `ShaderEffect`. You only need to write the color transformation — the vertex shader and texture sampling are handled automatically. Runs on both GPU backends — write the body once and it is realized as GLSL or WGSL for the active renderer — and is silently ignored in Canvas mode.
@@ -129,7 +129,40 @@ mySprite.addPostEffect(new ShaderEffect(renderer, `
}
`));
```
-See: [`ShaderEffect`](classes/ShaderEffect.html), [`addPostEffect`](classes/Renderable.html#addposteffect)
+See: {@link ShaderEffect | ShaderEffect}, {@link Renderable.addPostEffect | addPostEffect}
+
+## Using this reference with an AI assistant
+
+Three things here are meant for assistants as much as for people.
+
+**`llms.txt`** — [melonjs.github.io/melonJS/llms.txt](https://melonjs.github.io/melonJS/llms.txt)
+indexes every exported class, function, interface and type with a one-line
+summary and a link to its page, and marks the deprecated ones. It is
+regenerated on every docs build, so it never drifts from the release. Point an
+assistant at that single URL rather than asking it to guess an API name.
+
+**Copy page** — the button in the header above copies the page you are reading
+as Markdown, with its canonical URL attached, or hands it straight to an
+assistant. Useful when you want to ask about one class without the model
+fetching half the reference.
+
+**Skills** — the engine ships guidance files that teach an assistant its
+conventions, and more usefully the mistakes that fail *silently* rather than
+raising an error: a custom `draw()` that ignores `this.pos`, `isKinematic`
+blocking pointer events, `.z` set after `addChild`. They are versioned with the
+engine, so a copy matching your exact release always ships inside the package.
+
+Install them into whatever assistant you use, with one command:
+
+```bash
+npx skills add https://github.com/melonjs/melonJS/tree/master/packages/melonjs/skills
+```
+
+That writes each agent's own convention — `.claude/skills/`, `.agents/skills/`,
+`.windsurf/skills/` and around seventy others — so there is nothing to place by
+hand. It installs from `master`; swap that for a release tag in the URL to pin.
+
+They are plain Markdown — readable by any agent, or by you.
## Links
diff --git a/README.md b/README.md
index 6f502464c4..3fd33c5d01 100644
--- a/README.md
+++ b/README.md
@@ -331,32 +331,30 @@ melonJS ships **skills** — guidance files that teach AI coding assistants the
engine's conventions and, more usefully, the mistakes that fail silently rather
than raising an error.
-They are installed with the package, at `node_modules/melonjs/skills/`, and are
-versioned with the engine — so the guidance always matches the release you have.
+They are versioned with the engine and ship inside the package, at
+`node_modules/melonjs/skills/` — so a copy matching the exact release you are
+running is always on disk.
-**Claude Code** — install as a plugin :
-
-```
-/plugin marketplace add melonjs/melonJS
-```
-
-or copy the skills into a project :
+Install them into whatever assistant you use, with one command :
```bash
-mkdir -p .claude/skills && cp -r node_modules/melonjs/skills/melonjs* .claude/skills/
+npx skills add https://github.com/melonjs/melonJS/tree/master/packages/melonjs/skills
```
-**Other agents** (Codex, Cursor, Gemini CLI, …) read an `AGENTS.md` from your own
-project root. One ships ready to use — copy it across :
+It detects the assistants in your project and writes each one's own convention
+— `.claude/skills/`, `.agents/skills/`, `.windsurf/skills/` and around seventy
+others — so there is nothing to place by hand. Add `-a claude-code -a cursor`
+to target specific ones.
-```bash
-cp node_modules/melonjs/skills/AGENTS.md ./AGENTS.md
-```
-
-It points at the shipped skills, names the three rules that produce code which
-runs and is wrong, and links the API index below. If you already have an
+The set includes an `AGENTS.md` for anything following that convention (Codex,
+Cursor, Gemini CLI); GitHub Copilot reads the same content from
+`.github/copilot-instructions.md`. It names the three rules that produce code
+which runs and is wrong, and links the API index below — if you already keep an
`AGENTS.md`, paste its sections into yours.
+The command installs from `master`. To pin to the release you are running,
+point it at that tag instead of `master` in the URL above.
+
The skills are plain markdown and can be read by any agent, or by a human.
For anything the skills do not cover, the complete API is indexed for agents at
diff --git a/packages/melonjs/.gitignore b/packages/melonjs/.gitignore
index 93817e4cb6..50a61f6541 100644
--- a/packages/melonjs/.gitignore
+++ b/packages/melonjs/.gitignore
@@ -1,2 +1,3 @@
# copied from repo root during dist/publish
README.md
+.docs.css
diff --git a/packages/melonjs/CHANGELOG.md b/packages/melonjs/CHANGELOG.md
index febf4ea427..a628f74abc 100644
--- a/packages/melonjs/CHANGELOG.md
+++ b/packages/melonjs/CHANGELOG.md
@@ -9,7 +9,12 @@
- Mesh: `settings.vertexColors` and `setVertexColor(index, color)` give procedural geometry a per-vertex colour, multiplied into `tint`. Both batchers already wrote a per-vertex `aColor` on WebGL and WebGPU, but the array could only ever be built internally from a multi-material OBJ — so a mesh you built yourself had no way to reach it. `tint` is per *object*, so a terrain built as one mesh could only be tinted whole; this is what lets it fade toward the sky with distance, or darken in a crease, without splitting the mesh or writing a shader. Takes packed RGBA8 (`Uint32Array`, the form the batchers read) or one `Color` per vertex; a length that does not match the vertex count throws rather than mis-colouring the tail ([#1624](https://github.com/melonjs/melonJS/issues/1624))
- Mesh: normals are generated from the geometry when a `lit` mesh is built without them. A lit mesh with no normals had nothing for the shader to light with and rendered **fullbright** — asking for lighting and silently getting flat colour — and every hand-built mesh had to write the same accumulate-and-normalize loop first. Flat versus smooth is decided by the geometry rather than a flag: face normals accumulate into their vertices weighted by area, so shared vertices average into smooth shading while a triangle soup (each face owning its three vertices) resolves to the face normal and shades flat. An explicit `settings.normals` still wins, and an unlit mesh gets none
+### Added
+- Docs: the API reference carries the engine's own identity — logo, brand palette and favicon — and the header links out to the site, the wiki, the repository and Discord. A **Copy page** control hands the page you are reading to an assistant: it copies the page as Markdown with its canonical URL attached, or opens it directly in a chat. The landing page also gained a short section on using the reference with an AI assistant, covering that control, the `llms.txt` index and the shipped skills
+
### Fixed
+- Docs: a pass over the reference build itself, which was emitting 311 warnings. Thirteen links on the landing page were written as relative HTML paths that TypeDoc neither copies nor rewrites, so they 404'd for readers; 78 `@param` blocks documented parameters their signature did not declare — abstract stubs written as `drawTile()` with four documented arguments, so the published page showed none of them — and 70 legacy JSDoc tags left over from the previous toolchain were ignored with a warning apiece. Down to 156, with no reader-facing link left broken
+- Docs: engine internals no longer appear in the API reference or in consumers' autocomplete. Two different leaks with the same symptom: `@ignore` hides a member from the generated documentation but leaves it in the emitted `.d.ts`, and 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 all being offered as things to use, and the genuinely public surface was buried among them. Every `@ignore`d declaration is now also `@internal`, and the declaration stripper additionally drops class members whose name starts with `_` — this codebase's own convention for "not part of the API", applied consistently so it covers the ones nobody tagged and any added later. **1454 declarations left the published types and 89 left the reference, with no change to the public API** ([#1637](https://github.com/melonjs/melonJS/issues/1637))
- Audio: a game with a sound in its preload could hang on a blank loading screen, in four different ways. A clip that failed to load never reported anything at all unless the failure was a transport error: the listener required a numeric voice id, and a decode failure, a missing codec or a no-audio-support error all carry none — so a file served as HTML by an SPA rewrite, or a corrupt one, silently stalled the whole preload. With `stopOnAudioError = false` — "ignore audio errors and carry on" — a clip that did report called the loader's *error* callback, which for a promise-based preload is the reject: `Promise.all` rejected and the completion handler never ran. `preload: false` asks the backend not to fetch, so neither callback ever fired and the manifest waited on a clip that was never coming. And `loader.setOptions({ withCredentials: true })` reached the audio backend under a pre-20.3 name it does not read, so an authenticated request went out without its cookie and failed. Unloading a clip part-way through its retries also left its retry budget behind, so reloading the same name gave up on its first failure
- Audio: `xhrWithCredentials` still works on `Sound` itself, deprecated rather than removed, since games pass it straight through; `xhr: { withCredentials }` is the current spelling and wins when both are given
- Audio: a failed load no longer throws from a timer callback. The documented "throws" could not be caught by anyone — it landed on an empty stack as an uncaught global error — so the failure is now reported to the loader (which rejects the preload, the signal a caller actually catches) and logged with `console.error`. No working code can depend on the old form, since nothing could catch it
diff --git a/packages/melonjs/package.json b/packages/melonjs/package.json
index 486cdad0c4..e22b49f342 100644
--- a/packages/melonjs/package.json
+++ b/packages/melonjs/package.json
@@ -77,12 +77,13 @@
"build": "pnpm lint && tsx scripts/build.js && pnpm types",
"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",
"serve": "serve docs",
"prepublishOnly": "pnpm dist:publish",
"clean": "tsx scripts/clean.ts",
"types": "tsc --project tsconfig.build.json && tsx scripts/strip-internal.ts",
- "test:types": "tsc"
+ "test:types": "tsc",
+ "doc:css": "cat scripts/docs/brand.css scripts/docs/copy-page.css > scripts/docs/.docs.css"
}
}
diff --git a/packages/melonjs/scripts/docs/brand.css b/packages/melonjs/scripts/docs/brand.css
new file mode 100644
index 0000000000..2572fae30b
--- /dev/null
+++ b/packages/melonjs/scripts/docs/brand.css
@@ -0,0 +1,93 @@
+/*
+ * melonJS branding for the generated reference.
+ *
+ * The palette is sampled from the logo itself rather than invented: #6ba831 is
+ * the ring, #d1655b the dot, #202020 the ink (the same value the README and
+ * the engine's own default background use).
+ */
+:root {
+ --mjs-green: #6ba831;
+ --mjs-green-bright: #86c94a;
+ --mjs-melon: #d1655b;
+ --mjs-ink: #202020;
+}
+
+/* light */
+:root {
+ --color-link: #4f7f22;
+ --color-accent: #e7ecdf;
+ --color-active-menu-item: #e7ecdf;
+ --color-focus-outline: var(--mjs-green);
+ --color-ts-class: #4f7f22;
+ --color-ts-interface: #b1473c;
+}
+
+/* dark */
+:root[data-theme="dark"],
+body.dark {
+ --color-background: var(--mjs-ink);
+ --color-background-secondary: #2a2a2a;
+ --color-link: var(--mjs-green-bright);
+ --color-accent: #3a4032;
+ --color-active-menu-item: #39412e;
+ --color-ts-class: var(--mjs-green-bright);
+ --color-ts-interface: #e08c84;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root:not([data-theme="light"]) {
+ --color-background: var(--mjs-ink);
+ --color-background-secondary: #2a2a2a;
+ --color-link: var(--mjs-green-bright);
+ --color-accent: #3a4032;
+ --color-active-menu-item: #39412e;
+ --color-ts-class: var(--mjs-green-bright);
+ --color-ts-interface: #e08c84;
+ }
+}
+
+/* the logo, beside the wordmark in the toolbar */
+.tsd-toolbar-contents .title {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.5em;
+ font-weight: 700;
+ letter-spacing: 0.01em;
+}
+
+.tsd-toolbar-contents .title::before {
+ content: "";
+ width: 1.6em;
+ height: 1.6em;
+ flex: none;
+ background: url("data:image/svg+xml,%3Csvg%20width%3D%221475%22%20height%3D%221475%22%20viewBox%3D%220%200%201475%201475%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%20%3Crect%20width%3D%221475%22%20height%3D%221475%22%20fill%3D%22%23202020%22%2F%3E%20%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M523.521%20226.514C403.301%20277.234%20304.823%20368.927%20245.482%20485.398C186.141%20601.869%20169.756%20735.622%20199.22%20863.033C228.684%20990.444%20302.102%201103.31%20406.506%201181.71C510.909%201260.1%20639.58%201298.97%20769.791%201291.45C900.002%201283.93%201023.37%201230.51%201118.12%201140.62C1212.86%201050.73%201272.87%20930.156%201287.56%20800.195C1302.25%20670.235%201270.66%20539.251%201198.38%20430.38C1187.99%20414.724%201192.22%20393.582%201207.83%20383.159C1223.44%20372.736%201244.53%20376.978%201254.92%20392.634C1336.08%20514.876%201371.54%20661.945%201355.05%20807.866C1338.56%20953.786%201271.17%201089.17%201164.8%201190.1C1058.42%201291.02%20919.897%201351.01%20773.695%201359.45C627.494%201367.89%20483.021%201324.25%20365.796%201236.23C248.571%201148.21%20166.137%201021.48%20133.054%20878.42C99.9717%20735.362%20118.369%20585.183%20184.998%20454.409C251.626%20323.634%20362.197%20220.68%20497.181%20163.731C632.166%20106.783%20782.877%2099.5035%20922.694%20143.18C940.601%20148.774%20950.596%20167.866%20945.017%20185.824C939.439%20203.781%20920.4%20213.804%20902.493%20208.21C777.968%20169.311%20643.741%20175.793%20523.521%20226.514Z%22%20fill%3D%22%236BA831%22%2F%3E%20%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M1099.7%20309.488C1119.94%20309.488%201136.34%20293.208%201136.34%20273.126C1136.34%20253.044%201119.94%20236.764%201099.7%20236.764C1079.47%20236.764%201063.06%20253.044%201063.06%20273.126C1063.06%20293.208%201079.47%20309.488%201099.7%20309.488ZM752.797%20623.683C784.728%20591.995%20823.368%20576.144%20868.705%20576.144C914.042%20576.144%20952.669%20591.995%20984.6%20623.683C1016.53%20655.372%201032.5%20693.705%201032.5%20738.698V867.804C1032.5%20886.267%201017.42%20901.251%20998.801%20901.251C978.634%20901.251%20962.296%20885.038%20962.296%20865.038V740.262C962.296%20716.965%20954.311%20694.016%20938.495%20676.795C920.465%20657.156%20898.551%20646.852%20872.743%20645.882C844.499%20644.822%20816.881%20656.652%20798.134%20677.661C782.774%20694.856%20775.1%20715.206%20775.1%20738.698V866.68C775.1%20885.762%20759.493%20901.251%20740.251%20901.251C720.722%20901.251%20704.893%20885.556%20704.893%20866.175V738.698C704.893%20715.206%20697.233%20694.869%20681.873%20677.661C663.126%20656.652%20635.508%20644.822%20607.263%20645.882C581.468%20646.852%20559.569%20657.143%20541.525%20676.756C525.696%20693.977%20517.697%20716.939%20517.697%20740.236V866.641C517.697%20885.749%20502.09%20901.251%20482.835%20901.251C463.32%20901.251%20447.504%20885.568%20447.504%20866.188V738.698C447.504%20693.705%20463.463%20655.372%20495.407%20623.683C527.325%20591.995%20565.965%20576.144%20611.302%20576.144C656.639%20576.144%20695.266%20591.995%20727.197%20623.683C731.835%20628.273%20736.095%20632.979%20739.99%20637.828C743.898%20632.979%20748.159%20628.273%20752.797%20623.683Z%22%20fill%3D%22%23D1655B%22%2F%3E%20%3C%2Fsvg%3E") center / contain no-repeat;
+}
+
+/* a brand rule under the toolbar, instead of the default flat border */
+.tsd-page-toolbar {
+ border-bottom: 2px solid var(--mjs-green);
+}
+
+/* headings carry the brand rather than the theme default */
+.tsd-page-title h1,
+.col-content h2 {
+ letter-spacing: -0.01em;
+}
+
+.col-content h2 {
+ border-bottom: 1px solid var(--color-accent);
+ padding-bottom: 0.25em;
+}
+
+/* signatures read as code, so give them a surface of their own */
+.tsd-signature {
+ border-left: 3px solid var(--mjs-green);
+ border-radius: 0 4px 4px 0;
+}
+
+/* the melon dot for the "defined in" source links */
+.tsd-anchor-icon svg,
+a.tsd-index-link svg {
+ color: var(--mjs-melon);
+}
+
diff --git a/packages/melonjs/scripts/docs/copy-page.css b/packages/melonjs/scripts/docs/copy-page.css
new file mode 100644
index 0000000000..830d8b62af
--- /dev/null
+++ b/packages/melonjs/scripts/docs/copy-page.css
@@ -0,0 +1,88 @@
+/* "Copy page" control in the docs toolbar — see scripts/docs/copy-page.js */
+.mjs-copy-page {
+ position: relative;
+ display: inline-flex;
+ align-items: stretch;
+ margin-left: auto;
+ font-size: 0.875rem;
+}
+
+.mjs-copy-page-main,
+.mjs-copy-page-toggle {
+ background: var(--color-accent);
+ color: var(--color-text);
+ border: 1px solid var(--color-accent);
+ cursor: pointer;
+ padding: 0.35em 0.75em;
+ line-height: 1.3;
+ font: inherit;
+}
+
+.mjs-copy-page-main {
+ border-radius: 6px 0 0 6px;
+ border-right: none;
+}
+
+.mjs-copy-page-toggle {
+ border-radius: 0 6px 6px 0;
+ padding-inline: 0.5em;
+}
+
+.mjs-copy-page-main:hover,
+.mjs-copy-page-toggle:hover {
+ filter: brightness(1.15);
+}
+
+/* an author `display` beats the UA stylesheet's `[hidden] { display: none }`,
+ so the attribute alone would never hide this — state the hidden case too */
+.mjs-copy-page-menu[hidden] {
+ display: none;
+}
+
+.mjs-copy-page-menu {
+ position: absolute;
+ top: calc(100% + 6px);
+ right: 0;
+ z-index: 20;
+ min-width: 17rem;
+ display: flex;
+ flex-direction: column;
+ padding: 0.4em;
+ border-radius: 8px;
+ background: var(--color-background);
+ border: 1px solid var(--color-accent);
+ box-shadow: 0 8px 24px rgb(0 0 0 / 35%);
+}
+
+.mjs-copy-page-item {
+ display: flex;
+ flex-direction: column;
+ gap: 0.15em;
+ align-items: flex-start;
+ padding: 0.5em 0.6em;
+ border: 0;
+ border-radius: 6px;
+ background: transparent;
+ color: var(--color-text);
+ cursor: pointer;
+ text-align: left;
+ font: inherit;
+}
+
+.mjs-copy-page-item:hover {
+ background: var(--color-accent);
+}
+
+.mjs-copy-page-item small {
+ color: var(--color-text-aside);
+}
+
+/* the toolbar is a grid on narrow viewports — keep the control from stretching */
+@media (max-width: 769px) {
+ .mjs-copy-page {
+ margin-left: 0.5em;
+ }
+ .mjs-copy-page-item small {
+ display: none;
+ }
+}
diff --git a/packages/melonjs/scripts/docs/copy-page.js b/packages/melonjs/scripts/docs/copy-page.js
new file mode 100644
index 0000000000..0295a8cb03
--- /dev/null
+++ b/packages/melonjs/scripts/docs/copy-page.js
@@ -0,0 +1,133 @@
+/**
+ * "Copy page" — hand this page to an assistant.
+ *
+ * TypeDoc emits HTML, but what an assistant wants is the prose. This lifts the
+ * page's own content into Markdown and either copies it, or opens it in a chat
+ * with the canonical URL attached so the model can fetch the rest.
+ *
+ * Injected via `--customJs`; the styling lives in `copy-page.css`.
+ */
+(() => {
+ const PROMPT = "Read the melonJS API reference page at";
+
+ /** the page's main content, as Markdown */
+ const toMarkdown = (root) => {
+ const out = [];
+ const walk = (node, depth) => {
+ for (const el of node.children) {
+ const tag = el.tagName.toLowerCase();
+ if (tag === "a" && el.classList.contains("tsd-anchor")) continue;
+ const h = /^h([1-6])$/.exec(tag);
+ if (h) {
+ out.push(`\n${"#".repeat(+h[1])} ${el.textContent.trim()}\n`);
+ } else if (tag === "pre") {
+ out.push(`\n\`\`\`js\n${el.textContent.replace(/\n+$/, "")}\n\`\`\`\n`);
+ } else if (tag === "p" || tag === "li") {
+ const t = el.textContent.trim().replace(/\s+/g, " ");
+ if (t) out.push(tag === "li" ? `- ${t}` : `\n${t}\n`);
+ } else if (el.children.length) {
+ walk(el, depth + 1);
+ }
+ }
+ };
+ walk(root, 0);
+ return out.join("\n").replace(/\n{3,}/g, "\n\n").trim();
+ };
+
+ const pageMarkdown = () => {
+ const main = document.querySelector(".col-content") ?? document.body;
+ const title = document.querySelector("h1")?.textContent.trim() ?? document.title;
+ return `# ${title}\n\nSource: ${location.href}\n\n${toMarkdown(main)}`;
+ };
+
+ const open = (base) => {
+ const q = `${PROMPT} ${location.href} and help me use this API.`;
+ globalThis.open(`${base}${encodeURIComponent(q)}`, "_blank", "noopener");
+ };
+
+ const build = () => {
+ const header = document.querySelector(".tsd-toolbar-contents");
+ if (!header || document.querySelector(".mjs-copy-page")) return;
+
+ const wrap = document.createElement("div");
+ wrap.className = "mjs-copy-page";
+
+ const copy = document.createElement("button");
+ copy.type = "button";
+ copy.className = "mjs-copy-page-main";
+ copy.textContent = "Copy page";
+ copy.addEventListener("click", async () => {
+ try {
+ await navigator.clipboard.writeText(pageMarkdown());
+ copy.textContent = "Copied";
+ } catch {
+ // clipboard blocked (insecure origin, or the user said no)
+ copy.textContent = "Copy failed";
+ }
+ setTimeout(() => {
+ copy.textContent = "Copy page";
+ }, 1600);
+ });
+
+ const toggle = document.createElement("button");
+ toggle.type = "button";
+ toggle.className = "mjs-copy-page-toggle";
+ toggle.setAttribute("aria-label", "More options");
+ toggle.setAttribute("aria-expanded", "false");
+ toggle.textContent = "▾";
+
+ const menu = document.createElement("div");
+ menu.className = "mjs-copy-page-menu";
+ menu.hidden = true;
+ for (const [label, sub, url] of [
+ ["Open in ChatGPT", "Ask questions about this page", "https://chatgpt.com/?q="],
+ ["Open in Claude", "Ask questions about this page", "https://claude.ai/new?q="],
+ ]) {
+ const item = document.createElement("button");
+ item.type = "button";
+ item.className = "mjs-copy-page-item";
+ item.innerHTML = `${label}${sub}`;
+ item.addEventListener("click", () => {
+ menu.hidden = true;
+ toggle.setAttribute("aria-expanded", "false");
+ open(url);
+ });
+ menu.appendChild(item);
+ }
+
+ const setOpen = (open) => {
+ menu.hidden = !open;
+ toggle.setAttribute("aria-expanded", String(open));
+ };
+ toggle.addEventListener("click", () => {
+ setOpen(menu.hidden);
+ });
+ // Close on any click outside the control. Deliberately a containment
+ // test rather than `stopPropagation` on the toggle: that made closing
+ // depend on listener order, so a stray handler between the two — or a
+ // click landing on the wrapper rather than the button — could leave
+ // the menu stuck open.
+ document.addEventListener("click", (e) => {
+ if (!wrap.contains(e.target)) {
+ setOpen(false);
+ }
+ });
+ copy.addEventListener("click", () => {
+ setOpen(false);
+ });
+ document.addEventListener("keydown", (e) => {
+ if (e.key === "Escape") {
+ setOpen(false);
+ }
+ });
+
+ wrap.append(copy, toggle, menu);
+ header.appendChild(wrap);
+ };
+
+ if (document.readyState === "loading") {
+ document.addEventListener("DOMContentLoaded", build);
+ } else {
+ build();
+ }
+})();
diff --git a/packages/melonjs/scripts/strip-internal.ts b/packages/melonjs/scripts/strip-internal.ts
index 211759bf2b..e25150b6c4 100644
--- a/packages/melonjs/scripts/strip-internal.ts
+++ b/packages/melonjs/scripts/strip-internal.ts
@@ -32,12 +32,50 @@ function isInternal(node: ts.Node): boolean {
.some((tag) => tag.tagName.getText() === "internal");
}
+/** cheap pre-filter for the underscore rule below */
+const UNDERSCORE_HINT = /^\s*(readonly\s+)?_[A-Za-z0-9_]+\s*[?:(<]/m;
+
+/**
+ * A class member whose name starts with `_`.
+ *
+ * The underscore prefix is this codebase's own convention for "not part of the
+ * API", and it is used consistently — but only some of those members carry a
+ * doc tag, so tagging alone left hundreds of them in consumers' autocomplete.
+ * Treating the prefix as the declaration it already is covers them all,
+ * including any added later, without a tag on every one.
+ *
+ * Deliberately limited to class members: a module-level `_name` is not emitted
+ * unless exported, and an exported one is a public decision rather than an
+ * accident.
+ * @param node - the declaration under consideration
+ * @returns true when the member is private by naming convention
+ */
+function isUnderscoreMember(node: ts.Node): boolean {
+ // Class members only. NOT 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.
+ // `SpatialSoundState._pos` and its siblings are real cases here.
+ if (
+ !ts.isPropertyDeclaration(node) &&
+ !ts.isMethodDeclaration(node) &&
+ !ts.isGetAccessorDeclaration(node) &&
+ !ts.isSetAccessorDeclaration(node)
+ ) {
+ return false;
+ }
+ const name = node.name;
+ return (
+ (ts.isIdentifier(name) || ts.isPrivateIdentifier(name)) &&
+ name.text.startsWith("_")
+ );
+}
+
let filesTouched = 0;
let membersStripped = 0;
for (const path of walkFiles(ROOT)) {
const text = readFileSync(path, "utf8");
- if (!text.includes("@internal")) {
+ if (!text.includes("@internal") && !UNDERSCORE_HINT.test(text)) {
continue;
}
const source = ts.createSourceFile(path, text, ts.ScriptTarget.Latest, true);
@@ -47,7 +85,7 @@ for (const path of walkFiles(ROOT)) {
// class members plus top-level statements
const ranges: Array<{ start: number; end: number }> = [];
const collect = (node: ts.Node) => {
- if (isInternal(node)) {
+ if (isInternal(node) || isUnderscoreMember(node)) {
ranges.push({ start: node.getFullStart(), end: node.getEnd() });
return; // no need to descend into a removed subtree
}
diff --git a/packages/melonjs/src/application/application.ts b/packages/melonjs/src/application/application.ts
index d38182268b..dedcab805b 100644
--- a/packages/melonjs/src/application/application.ts
+++ b/packages/melonjs/src/application/application.ts
@@ -85,6 +85,7 @@ type DocumentWithLegacyExitFullscreen = Document & {
* `physics/collision.js`, which imports the `game` reference back from
* this module.
* @ignore
+ * @internal
*/
function resolvePhysicSetting(physic: ApplicationSettings["physic"]): {
adapter: PhysicsAdapter | undefined;
@@ -228,15 +229,39 @@ export default class Application {
stepSize: number;
// DOM event handlers (stored for cleanup in destroy)
+ /**
+ * @ignore
+ * @internal
+ */
private _onResize?: (e: Event) => void;
+ /**
+ * @ignore
+ * @internal
+ */
private _onOrientationChange?: (e: Event) => void;
+ /**
+ * @ignore
+ * @internal
+ */
private _onScroll?: (e: Event) => void;
// melonJS-event resize subscription (stored for cleanup in destroy)
+ /**
+ * @ignore
+ * @internal
+ */
private _doResize?: () => void;
// the parent-element observer installed by init() (disconnected in destroy)
+ /**
+ * @ignore
+ * @internal
+ */
private _resizeObserver: MutationObserver | undefined;
// set by destroy(); a destroyed Application is terminal — init() refuses
// to run (or, if already in flight, aborts) instead of resurrecting it
+ /**
+ * @ignore
+ * @internal
+ */
private _destroyed = false;
/**
* Simulated time advanced by one logic step, in ms — what `world.update()`
@@ -1030,13 +1055,19 @@ export default class Application {
return state.freeze(duration, music);
}
- /** @ignore */
+ /**
+ * @ignore
+ * @internal
+ */
_tick(time: number): void {
this.update(time);
this.draw();
}
- /** @ignore */
+ /**
+ * @ignore
+ * @internal
+ */
_onBlur(): void {
if (this.stopOnBlur) {
state.stop(true);
@@ -1046,7 +1077,10 @@ export default class Application {
}
}
- /** @ignore */
+ /**
+ * @ignore
+ * @internal
+ */
_onFocus(): void {
if (this.stopOnBlur) {
state.restart(true);
@@ -1165,6 +1199,7 @@ export let game: Application;
/**
* Set the default game application instance.
* @ignore
+ * @internal
*/
export function setDefaultGame(app: Application) {
game = app;
diff --git a/packages/melonjs/src/application/settings.ts b/packages/melonjs/src/application/settings.ts
index 607d124874..f9af19d99e 100644
--- a/packages/melonjs/src/application/settings.ts
+++ b/packages/melonjs/src/application/settings.ts
@@ -395,6 +395,9 @@ export type ApplicationSettings = {
/**
* Resolved application settings after init() has processed the input.
* Includes computed properties not present in the user-facing settings.
+ * Hidden from the docs but deliberately kept in the emitted `.d.ts`: another
+ * emitted declaration imports this type, so removing it would leave a dangling
+ * import in the published types.
* @ignore
*/
export type ResolvedApplicationSettings = ApplicationSettings & {
diff --git a/packages/melonjs/src/audio/backend/engine.ts b/packages/melonjs/src/audio/backend/engine.ts
index 3469295f2f..58ceeddfaa 100644
--- a/packages/melonjs/src/audio/backend/engine.ts
+++ b/packages/melonjs/src/audio/backend/engine.ts
@@ -8,14 +8,42 @@ import {
} from "./types.ts";
export class AudioEngine {
+ /**
+ * @ignore
+ * @internal
+ */
_counter: number = 1000;
+ /**
+ * @ignore
+ * @internal
+ */
_html5AudioPool: HTMLAudioElement[] = [];
html5PoolSize: number = 10;
+ /**
+ * @ignore
+ * @internal
+ */
_codecs: Record = {};
sounds: Sound[] = [];
+ /**
+ * @ignore
+ * @internal
+ */
_muted: boolean = false;
+ /**
+ * @ignore
+ * @internal
+ */
_volume: number = 1;
+ /**
+ * @ignore
+ * @internal
+ */
_canPlayEvent: string = "canplaythrough";
+ /**
+ * @ignore
+ * @internal
+ */
_navigator: Navigator | null = null;
masterGain: GainNode | null = null;
noAudio: boolean = false;
@@ -24,10 +52,30 @@ export class AudioEngine {
ctx: AudioContext | null = null;
autoUnlock: boolean = true;
state: string = "suspended";
+ /**
+ * @ignore
+ * @internal
+ */
_audioUnlocked: boolean = false;
+ /**
+ * @ignore
+ * @internal
+ */
_scratchBuffer: AudioBuffer | null = null;
+ /**
+ * @ignore
+ * @internal
+ */
_suspendTimer: ReturnType | null = null;
+ /**
+ * @ignore
+ * @internal
+ */
_resumeAfterSuspend?: boolean;
+ /**
+ * @ignore
+ * @internal
+ */
_mobileUnloaded?: boolean;
constructor() {
diff --git a/packages/melonjs/src/audio/backend/sound.ts b/packages/melonjs/src/audio/backend/sound.ts
index 3b4ee04048..70e3959b8d 100644
--- a/packages/melonjs/src/audio/backend/sound.ts
+++ b/packages/melonjs/src/audio/backend/sound.ts
@@ -14,42 +14,174 @@ import {
import { Voice } from "./voice.ts";
class Sound {
+ /**
+ * @ignore
+ * @internal
+ */
_autoplay: boolean = false;
+ /**
+ * @ignore
+ * @internal
+ */
_format: string[] = [];
+ /**
+ * @ignore
+ * @internal
+ */
_html5: boolean = false;
+ /**
+ * @ignore
+ * @internal
+ */
_muted: boolean = false;
+ /**
+ * @ignore
+ * @internal
+ */
_loop: boolean = false;
+ /**
+ * @ignore
+ * @internal
+ */
_pool: number = 5;
+ /**
+ * @ignore
+ * @internal
+ */
_preload: boolean | "metadata" = true;
+ /**
+ * @ignore
+ * @internal
+ */
_rate: number = 1;
+ /**
+ * @ignore
+ * @internal
+ */
_sprite: Record = {};
+ /**
+ * @ignore
+ * @internal
+ */
_src: string | string[] = [];
+ /**
+ * @ignore
+ * @internal
+ */
_volume: number = 1;
+ /**
+ * @ignore
+ * @internal
+ */
_xhr: {
method: string;
headers?: HeadersInit | undefined;
withCredentials: boolean;
} = { method: "GET", withCredentials: false };
+ /**
+ * @ignore
+ * @internal
+ */
_duration: number = 0;
+ /**
+ * @ignore
+ * @internal
+ */
_state: string = "unloaded";
+ /**
+ * @ignore
+ * @internal
+ */
_sounds: Voice[] = [];
+ /**
+ * @ignore
+ * @internal
+ */
_endTimers: Record> = {};
+ /**
+ * @ignore
+ * @internal
+ */
_queue: QueueItem[] = [];
+ /**
+ * @ignore
+ * @internal
+ */
_playLock: boolean = false;
+ /**
+ * @ignore
+ * @internal
+ */
_webAudio: boolean = false;
+ /**
+ * @ignore
+ * @internal
+ */
_onend: EventListener[] = [];
+ /**
+ * @ignore
+ * @internal
+ */
_onfade: EventListener[] = [];
+ /**
+ * @ignore
+ * @internal
+ */
_onload: EventListener[] = [];
+ /**
+ * @ignore
+ * @internal
+ */
_onloaderror: EventListener[] = [];
+ /**
+ * @ignore
+ * @internal
+ */
_onplayerror: EventListener[] = [];
+ /**
+ * @ignore
+ * @internal
+ */
_onpause: EventListener[] = [];
+ /**
+ * @ignore
+ * @internal
+ */
_onplay: EventListener[] = [];
+ /**
+ * @ignore
+ * @internal
+ */
_onstop: EventListener[] = [];
+ /**
+ * @ignore
+ * @internal
+ */
_onmute: EventListener[] = [];
+ /**
+ * @ignore
+ * @internal
+ */
_onvolume: EventListener[] = [];
+ /**
+ * @ignore
+ * @internal
+ */
_onrate: EventListener[] = [];
+ /**
+ * @ignore
+ * @internal
+ */
_onseek: EventListener[] = [];
+ /**
+ * @ignore
+ * @internal
+ */
_onunlock: EventListener[] = [];
+ /**
+ * @ignore
+ * @internal
+ */
_onresume: EventListener[] = [];
constructor(o: SoundOptions) {
diff --git a/packages/melonjs/src/audio/backend/spatial.ts b/packages/melonjs/src/audio/backend/spatial.ts
index 6042f0f14a..ac50942831 100644
--- a/packages/melonjs/src/audio/backend/spatial.ts
+++ b/packages/melonjs/src/audio/backend/spatial.ts
@@ -77,9 +77,17 @@ export interface SpatialSoundOptions extends SoundOptions {
* @internal
*/
export interface SpatialAudioState {
- /** Listener's 3D position [x, y, z]. */
+ /**
+ * Listener's 3D position [x, y, z].
+ * @ignore
+ * @internal
+ */
_pos: [number, number, number];
- /** Listener's orientation [forwardX, forwardY, forwardZ, upX, upY, upZ]. */
+ /**
+ * Listener's orientation [forwardX, forwardY, forwardZ, upX, upY, upZ].
+ * @ignore
+ * @internal
+ */
_orientation: [number, number, number, number, number, number];
}
@@ -93,15 +101,35 @@ export interface SpatialSoundState {
_pos: [number, number, number] | null;
/** Voice source's orientation vector [x, y, z]. */
_orientation: [number, number, number];
- /** Stereo panning value from -1.0 to 1.0, or null if not set. */
+ /**
+ * Stereo panning value from -1.0 to 1.0, or null if not set.
+ * @ignore
+ * @internal
+ */
_stereo: number | null;
- /** Panner node attributes for 3D audio processing. */
+ /**
+ * Panner node attributes for 3D audio processing.
+ * @ignore
+ * @internal
+ */
_pannerAttr: PannerAttrOptions;
- /** Event listeners for stereo panning changes. */
+ /**
+ * Event listeners for stereo panning changes.
+ * @ignore
+ * @internal
+ */
_onstereo: Array<{ fn: () => void }>;
- /** Event listeners for position changes. */
+ /**
+ * Event listeners for position changes.
+ * @ignore
+ * @internal
+ */
_onpos: Array<{ fn: () => void }>;
- /** Event listeners for orientation changes. */
+ /**
+ * Event listeners for orientation changes.
+ * @ignore
+ * @internal
+ */
_onorientation: Array<{ fn: () => void }>;
}
diff --git a/packages/melonjs/src/audio/backend/types.ts b/packages/melonjs/src/audio/backend/types.ts
index f5530a0d56..ad169b3f7a 100644
--- a/packages/melonjs/src/audio/backend/types.ts
+++ b/packages/melonjs/src/audio/backend/types.ts
@@ -109,7 +109,11 @@ export interface QueueItem {
* @internal
*/
export interface HTMLAudioElementWithUnlocked extends HTMLAudioElement {
- /** Internal flag indicating if the audio element has been unlocked for playback. */
+ /**
+ * Internal flag indicating if the audio element has been unlocked for playback.
+ * @ignore
+ * @internal
+ */
_unlocked?: boolean;
}
diff --git a/packages/melonjs/src/audio/backend/voice.ts b/packages/melonjs/src/audio/backend/voice.ts
index 2584280df0..2a21e01e36 100644
--- a/packages/melonjs/src/audio/backend/voice.ts
+++ b/packages/melonjs/src/audio/backend/voice.ts
@@ -8,26 +8,110 @@ import {
} from "./types.ts";
export class Voice {
+ /**
+ * @ignore
+ * @internal
+ */
_parent: Sound;
+ /**
+ * @ignore
+ * @internal
+ */
_muted: boolean = false;
+ /**
+ * @ignore
+ * @internal
+ */
_loop: boolean = false;
+ /**
+ * @ignore
+ * @internal
+ */
_volume: number = 1;
+ /**
+ * @ignore
+ * @internal
+ */
_rate: number = 1;
+ /**
+ * @ignore
+ * @internal
+ */
_seek: number = 0;
+ /**
+ * @ignore
+ * @internal
+ */
_paused: boolean = true;
+ /**
+ * @ignore
+ * @internal
+ */
_ended: boolean = true;
+ /**
+ * @ignore
+ * @internal
+ */
_sprite: string = "__default";
+ /**
+ * @ignore
+ * @internal
+ */
_id: number = 0;
+ /**
+ * @ignore
+ * @internal
+ */
_node: HTMLAudioElementWithUnlocked | GainNodeWithBufferSource | null = null;
+ /**
+ * @ignore
+ * @internal
+ */
_playStart: number = 0;
+ /**
+ * @ignore
+ * @internal
+ */
_rateSeek: number = 0;
+ /**
+ * @ignore
+ * @internal
+ */
_errorFn?: (event: Event) => void;
+ /**
+ * @ignore
+ * @internal
+ */
_loadFn?: (event: Event) => void;
+ /**
+ * @ignore
+ * @internal
+ */
_endFn?: (event: Event) => void;
+ /**
+ * @ignore
+ * @internal
+ */
_start?: number;
+ /**
+ * @ignore
+ * @internal
+ */
_stop?: number;
+ /**
+ * @ignore
+ * @internal
+ */
_panner?: PannerNode | StereoPannerNode;
+ /**
+ * @ignore
+ * @internal
+ */
_fadeTo?: number | undefined;
+ /**
+ * @ignore
+ * @internal
+ */
_interval?: ReturnType | undefined;
constructor(sound: Sound) {
diff --git a/packages/melonjs/src/audio/procedural.ts b/packages/melonjs/src/audio/procedural.ts
index 4f757c6756..55c1ea2564 100644
--- a/packages/melonjs/src/audio/procedural.ts
+++ b/packages/melonjs/src/audio/procedural.ts
@@ -26,6 +26,7 @@ import type { NoiseOptions, ToneOptions } from "./types.ts";
* unawaited because we want the same call site to work in both gesture
* and non-gesture contexts.
* @ignore
+ * @internal
*/
function _resumeIfSuspended(ctx: AudioContext): void {
if (ctx.state === "suspended") {
@@ -46,6 +47,7 @@ function _resumeIfSuspended(ctx: AudioContext): void {
* `InvalidStateError`) AND tiny positive gains where a target of
* `0.0001` would ramp UP and produce an audible click.
* @ignore
+ * @internal
*/
function _buildGainEnvelope(
ctx: AudioContext,
@@ -79,6 +81,7 @@ function _buildGainEnvelope(
* Returns the `StereoPannerNode` it created (or `null` if `pan === 0`)
* so the caller can disconnect it once playback ends.
* @ignore
+ * @internal
*/
function _connectToOutput(
ctx: AudioContext,
@@ -193,6 +196,7 @@ export function tone(opts: ToneOptions): void {
* brown is a leaky integrator over white. Output is roughly normalised
* to `[-1, 1]` for both coloured variants.
* @ignore
+ * @internal
*/
function fillNoiseBuffer(
data: Float32Array,
diff --git a/packages/melonjs/src/audio/state.ts b/packages/melonjs/src/audio/state.ts
index c045a69e2c..35ce3582a0 100644
--- a/packages/melonjs/src/audio/state.ts
+++ b/packages/melonjs/src/audio/state.ts
@@ -61,6 +61,7 @@ export function setStopOnAudioError(value: boolean): void {
* loads steal each other's retry budget).
* - `audioExts` — the active list of audio formats set by `init`.
* @ignore
+ * @internal
*/
export const state = {
tracks: {} as Record,
@@ -75,6 +76,7 @@ export const state = {
* Used by every per-clip helper across `playback.ts` / `audio.ts` so
* the error contract stays identical across the whole surface.
* @ignore
+ * @internal
*/
export function getSoundOrThrow(sound_name: string): SpatialSound {
const sound = state.tracks[sound_name];
@@ -91,6 +93,7 @@ export function getSoundOrThrow(sound_name: string): SpatialSound {
* is reported through a callback — nothing is thrown, because this runs from a
* timer callback where a throw could not be caught by anyone.
* @ignore
+ * @internal
*/
export const soundLoadError = function (
sound_name: string,
@@ -190,6 +193,7 @@ export function getMasterGain(): GainNode | null {
/**
* Get the audio module's global volume.
* @ignore
+ * @internal
*/
export function getGlobalVolume(): number {
return audioEngine.volume() as number;
@@ -198,6 +202,7 @@ export function getGlobalVolume(): number {
/**
* Set the audio module's global volume.
* @ignore
+ * @internal
*/
export function setGlobalVolume(v: number): void {
audioEngine.volume(v);
@@ -206,6 +211,7 @@ export function setGlobalVolume(v: number): void {
/**
* Mute or unmute the audio module globally.
* @ignore
+ * @internal
*/
export function setGlobalMuted(muted: boolean): void {
audioEngine.mute(muted);
@@ -214,6 +220,7 @@ export function setGlobalMuted(muted: boolean): void {
/**
* Whether the audio module is currently muted globally.
* @ignore
+ * @internal
*/
export function isGlobalMuted(): boolean {
// audioEngine doesn't expose a public muted getter — peek at the private
@@ -225,6 +232,7 @@ export function isGlobalMuted(): boolean {
/**
* Stop every playing sound on every channel.
* @ignore
+ * @internal
*/
export function stopAllPlayback(): void {
audioEngine.stop();
@@ -233,6 +241,7 @@ export function stopAllPlayback(): void {
/**
* Whether the given audio codec is supported by the backend / browser.
* @ignore
+ * @internal
*/
export function hasCodec(codec: string): boolean {
if (!isAudioAvailable()) return false;
@@ -246,6 +255,7 @@ export function hasCodec(codec: string): boolean {
/**
* Whether at least one audio backend (HTML5 or WebAudio) is available.
* @ignore
+ * @internal
*/
export function isAudioAvailable(): boolean {
return !audioEngine.noAudio;
diff --git a/packages/melonjs/src/camera/camera2d.ts b/packages/melonjs/src/camera/camera2d.ts
index 9f06c67452..3af653bcdf 100644
--- a/packages/melonjs/src/camera/camera2d.ts
+++ b/packages/melonjs/src/camera/camera2d.ts
@@ -140,6 +140,7 @@ export default class Camera2d extends Renderable {
/**
* @ignore
+ * @internal
*/
_zoom: number;
@@ -167,6 +168,7 @@ export default class Camera2d extends Renderable {
/**
* cached world view bounds
* @ignore
+ * @internal
*/
_worldView: Bounds;
@@ -179,6 +181,7 @@ export default class Camera2d extends Renderable {
/**
* the invert camera transform used to unproject points
* @ignore
+ * @internal
*/
invCurrentTransform: Matrix3d;
@@ -209,7 +212,10 @@ export default class Camera2d extends Renderable {
*/
colorMatrix: ColorMatrix;
- /** @ignore */
+ /**
+ * @ignore
+ * @internal
+ */
_colorMatrixEffect: ColorMatrixEffect | null;
/** the camera deadzone */
@@ -279,6 +285,10 @@ export default class Camera2d extends Renderable {
this.isKinematic = false;
// camera manages its own FBO lifecycle in draw()
+ /**
+ * @ignore
+ * @internal
+ */
this._postEffectManaged = true;
this.colorMatrix = new ColorMatrix();
@@ -299,7 +309,10 @@ export default class Camera2d extends Renderable {
// -- some private function ---
- /** @ignore */
+ /**
+ * @ignore
+ * @internal
+ */
// update the projection matrix based on the projection frame (a rectangle)
_updateProjectionMatrix(): void {
this.projectionMatrix.ortho(
@@ -320,7 +333,10 @@ export default class Camera2d extends Renderable {
this.screenProjection.copy(this.projectionMatrix);
}
- /** @ignore */
+ /**
+ * @ignore
+ * @internal
+ */
_followH(target: Vector2d | Vector3d): number {
let targetX = this.pos.x;
if (target.x - this.pos.x > this.deadzone.right) {
@@ -337,7 +353,10 @@ export default class Camera2d extends Renderable {
return targetX;
}
- /** @ignore */
+ /**
+ * @ignore
+ * @internal
+ */
_followV(target: Vector2d | Vector3d): number {
let targetY = this.pos.y;
if (target.y - this.pos.y > this.deadzone.bottom) {
@@ -607,7 +626,10 @@ export default class Camera2d extends Renderable {
}
}
- /** @ignore */
+ /**
+ * @ignore
+ * @internal
+ */
updateTarget(dt?: number): void {
if (this.target) {
@@ -660,7 +682,10 @@ export default class Camera2d extends Renderable {
}
}
- /** @ignore */
+ /**
+ * @ignore
+ * @internal
+ */
override update(dt?: number): boolean {
// update the camera position
this.updateTarget(dt);
@@ -913,6 +938,7 @@ export default class Camera2d extends Renderable {
* @param _renderer - the renderer about to draw with this camera
* @returns fog state, or null for no fog
* @ignore
+ * @internal
*/
_fog3dState(_renderer: Renderer): Fog3dState | null {
return null;
@@ -926,6 +952,7 @@ export default class Camera2d extends Renderable {
* viewport. Subclasses (e.g. Camera3d) override this to install a
* perspective `worldProjection` instead.
* @ignore
+ * @internal
*/
_setupNonDefaultProjection(renderer: Renderer): void {
const left = -this.screenX / this.zoom;
@@ -956,6 +983,7 @@ export default class Camera2d extends Renderable {
/**
* render the camera effects
* @ignore
+ * @internal
*/
drawFX(renderer: Renderer): void {
for (const fx of this.cameraEffects) {
@@ -966,6 +994,7 @@ export default class Camera2d extends Renderable {
/**
* draw all objects visible in this viewport
* @ignore
+ * @internal
*/
override draw(renderer: Renderer, container: Container): void {
// cast to any to access canvas/webgl renderer-specific methods not on base Renderer
@@ -1113,6 +1142,7 @@ export default class Camera2d extends Renderable {
* offset); Camera3d overrides this to additionally rotate by
* `-camera.pitch` / `-camera.yaw` in the correct order.
* @ignore
+ * @internal
*/
_applyContainerViewTransform(
container: Container,
@@ -1127,6 +1157,7 @@ export default class Camera2d extends Renderable {
* Must undo each mutation in reverse order. Subclasses overriding
* `_applyContainerViewTransform` should override this too.
* @ignore
+ * @internal
*/
_revertContainerViewTransform(
container: Container,
@@ -1138,6 +1169,7 @@ export default class Camera2d extends Renderable {
/**
* @ignore
+ * @internal
*/
override destroy(): void {
// unsubscribe the constructor-registered global listeners — without
diff --git a/packages/melonjs/src/camera/camera3d.ts b/packages/melonjs/src/camera/camera3d.ts
index fae6f50a6f..9659feb79c 100644
--- a/packages/melonjs/src/camera/camera3d.ts
+++ b/packages/melonjs/src/camera/camera3d.ts
@@ -111,6 +111,7 @@ export default class Camera3d extends Camera2d {
* the fog options as given to {@link Camera3d#setFog}, or `null` when fog
* is off. Read through the {@link Camera3d#fog} accessor.
* @ignore
+ * @internal
*/
private _fogOptions: FogOptions | null = null;
@@ -124,13 +125,29 @@ export default class Camera3d extends Camera2d {
* documented model — a `Color` is live, everything else is settled at the
* call — is now the real one.
* @ignore
+ * @internal
*/
private _fogMode: FogMode = "linear";
- /** @ignore */ private _fogNear: number | undefined = undefined;
- /** @ignore */ private _fogFar: number | undefined = undefined;
- /** @ignore */ private _fogDensity: number | undefined = undefined;
- /** @ignore */ private _fogHeight = 0;
- /** @ignore */ private _fogHeightFalloff = 0;
+ /**
+ * @ignore
+ * @internal
+ */ private _fogNear: number | undefined = undefined;
+ /**
+ * @ignore
+ * @internal
+ */ private _fogFar: number | undefined = undefined;
+ /**
+ * @ignore
+ * @internal
+ */ private _fogDensity: number | undefined = undefined;
+ /**
+ * @ignore
+ * @internal
+ */ private _fogHeight = 0;
+ /**
+ * @ignore
+ * @internal
+ */ private _fogHeightFalloff = 0;
/**
* Owned colour, used only when the caller passed a CSS string or an array.
@@ -138,6 +155,7 @@ export default class Camera3d extends Camera2d {
* default tracks `renderer.backgroundColor`, so in both of those cases
* this stays `null`.
* @ignore
+ * @internal
*/
private _fogOwnColor: Color | null = null;
@@ -145,6 +163,7 @@ export default class Camera3d extends Camera2d {
* Resolved fog handed to the renderer. Allocated once and rewritten in
* place each frame — fog costs no per-frame allocation.
* @ignore
+ * @internal
*/
private _fogState: Fog3dState = {
mode: 0,
@@ -429,12 +448,32 @@ export default class Camera3d extends Camera2d {
this._fogOptions = options;
this._fogMode = mode;
+ /**
+ * @ignore
+ * @internal
+ */
this._fogNear = options.near;
+ /**
+ * @ignore
+ * @internal
+ */
this._fogFar = options.far;
+ /**
+ * @ignore
+ * @internal
+ */
this._fogDensity = options.density;
+ /**
+ * @ignore
+ * @internal
+ */
this._fogHeight = options.fogHeight ?? 0;
// zero is uniform fog — the maths below collapses to the distance-only
// form exactly, so the default changes nothing
+ /**
+ * @ignore
+ * @internal
+ */
this._fogHeightFalloff = options.heightFalloff ?? 0;
// A `Color` is referenced so mutating it animates the fog; anything
// else is parsed once into a colour this camera owns.
@@ -496,6 +535,7 @@ export default class Camera3d extends Camera2d {
* a 2D camera clear fog rather than inherit whatever the previous camera
* left behind.
* @ignore
+ * @internal
*/
override _fog3dState(renderer: Renderer): Fog3dState | null {
const options = this._fogOptions;
@@ -608,6 +648,7 @@ export default class Camera3d extends Camera2d {
* base `Camera2d` constructor and by `resize()`. Camera3d's
* version replaces the ortho matrix with the frustum's perspective.
* @ignore
+ * @internal
*/
override _updateProjectionMatrix(): void {
// guard: this is called from the Camera2d super-constructor
@@ -659,6 +700,7 @@ export default class Camera3d extends Camera2d {
* because it was already set up correctly in
* {@link Camera3d#_updateProjectionMatrix}.
* @ignore
+ * @internal
*/
override _setupNonDefaultProjection(renderer: Renderer): void {
this.worldProjection.copy(this.projectionMatrix);
@@ -701,6 +743,7 @@ export default class Camera3d extends Camera2d {
* this subtracts the camera position then rotates by the camera's
* inverse orientation, which is the standard view transform.
* @ignore
+ * @internal
*/
override _applyContainerViewTransform(
container: Container,
@@ -752,6 +795,7 @@ export default class Camera3d extends Camera2d {
* order to restore the container's `currentTransform` to its
* pre-camera state.
* @ignore
+ * @internal
*/
override _revertContainerViewTransform(
container: Container,
@@ -877,6 +921,7 @@ export default class Camera3d extends Camera2d {
* showcase (AfterBurner's banking jet) demands it.
* @param dt - delta time in milliseconds (ignored — no damping)
* @ignore
+ * @internal
*/
override updateTarget(dt?: number): void {
const target = this.target;
@@ -1022,6 +1067,7 @@ export default class Camera3d extends Camera2d {
* @param dt - delta time in milliseconds
* @returns true if the camera's state changed
* @ignore
+ * @internal
*/
override update(dt?: number): boolean {
const dirty = super.update(dt);
@@ -1091,6 +1137,7 @@ export default class Camera3d extends Camera2d {
* Called from {@link Camera3d#update} each frame; `isVisible`
* then tests against the cached planes.
* @ignore
+ * @internal
*/
_rebuildFrustumPlanes(): void {
// build the view matrix R⁻¹ ∘ T(-pos) the same way
diff --git a/packages/melonjs/src/camera/effects/fade_effect.ts b/packages/melonjs/src/camera/effects/fade_effect.ts
index ac5a985934..694b179eb5 100644
--- a/packages/melonjs/src/camera/effects/fade_effect.ts
+++ b/packages/melonjs/src/camera/effects/fade_effect.ts
@@ -43,6 +43,7 @@ export default class FadeEffect extends CameraEffect {
/**
* target alpha value for completion check
* @ignore
+ * @internal
*/
_targetAlpha: number;
diff --git a/packages/melonjs/src/camera/effects/mask_effect.ts b/packages/melonjs/src/camera/effects/mask_effect.ts
index c39046dc99..a091a5d032 100644
--- a/packages/melonjs/src/camera/effects/mask_effect.ts
+++ b/packages/melonjs/src/camera/effects/mask_effect.ts
@@ -70,6 +70,7 @@ export default class MaskEffect extends CameraEffect {
/**
* pooled shape used for rendering (avoids per-frame allocation)
* @ignore
+ * @internal
*/
_maskShape: MaskShape;
diff --git a/packages/melonjs/src/camera/fog.ts b/packages/melonjs/src/camera/fog.ts
index 4d7c9bba29..ee29fcffad 100644
--- a/packages/melonjs/src/camera/fog.ts
+++ b/packages/melonjs/src/camera/fog.ts
@@ -80,6 +80,9 @@ export interface FogOptions {
/**
* The resolved per-frame fog values handed to the renderer. Distances are
* pre-baked into the form the shaders want so neither backend divides.
+ * Hidden from the docs but deliberately kept in the emitted `.d.ts`:
+ * `camera3d.d.ts` imports this type, so removing it would leave a dangling
+ * import in the published types.
* @ignore
*/
export interface Fog3dState {
diff --git a/packages/melonjs/src/geometries/box3d.ts b/packages/melonjs/src/geometries/box3d.ts
index a863d03855..662221daa7 100644
--- a/packages/melonjs/src/geometries/box3d.ts
+++ b/packages/melonjs/src/geometries/box3d.ts
@@ -9,6 +9,7 @@ import { Polygon } from "./polygon.ts";
* Smallest XY footprint edge handed to {@link Polygon#recalc}. See
* {@link Box3d#_syncFootprint} for why a zero-length edge is unsafe.
* @ignore
+ * @internal
*/
const MIN_FOOTPRINT = 1e-6;
@@ -73,6 +74,7 @@ export class Box3d {
* ({@link Body#bounds}, the broadphase pre-gate, debug draw) sees a
* plain rectangle and needs no 3D awareness.
* @ignore
+ * @internal
*/
_bounds: Bounds;
@@ -82,6 +84,7 @@ export class Box3d {
* hand this to the existing polygon SAT, so no polygon is allocated
* per collision test.
* @ignore
+ * @internal
*/
_footprint: Polygon;
@@ -144,6 +147,7 @@ export class Box3d {
* `renderable.pos + ancestor.getAbsolutePosition() + shape.pos` and
* then treats `points` as offsets from it.
* @ignore
+ * @internal
*/
_syncFootprint() {
const hx = this.halfExtents.x;
diff --git a/packages/melonjs/src/geometries/ellipse.ts b/packages/melonjs/src/geometries/ellipse.ts
index fa509a2e0b..7dcd4d7d53 100644
--- a/packages/melonjs/src/geometries/ellipse.ts
+++ b/packages/melonjs/src/geometries/ellipse.ts
@@ -16,6 +16,8 @@ export class Ellipse {
/**
* The bounding rectangle for this shape
+ * @ignore
+ * @internal
*/
_bounds: Bounds;
@@ -41,21 +43,29 @@ export class Ellipse {
/**
* the internal rotation angle of the ellipse in radians
+ * @ignore
+ * @internal
*/
private _angle: number;
/**
* cached cosine of the current angle
+ * @ignore
+ * @internal
*/
private _cos: number;
/**
* cached sine of the current angle
+ * @ignore
+ * @internal
*/
private _sin: number;
/**
* cached polygon approximation, invalidated when shape changes
+ * @ignore
+ * @internal
*/
private _polygon: Polygon | null = null;
diff --git a/packages/melonjs/src/geometries/observablePoint.ts b/packages/melonjs/src/geometries/observablePoint.ts
index d0fe1579ee..61681dcfcc 100644
--- a/packages/melonjs/src/geometries/observablePoint.ts
+++ b/packages/melonjs/src/geometries/observablePoint.ts
@@ -7,8 +7,20 @@ import { Point } from "./point.ts";
* Represents an observable point in 2D space.
*/
export class ObservablePoint {
+ /**
+ * @ignore
+ * @internal
+ */
private _callback: () => void;
+ /**
+ * @ignore
+ * @internal
+ */
private _point: Point;
+ /**
+ * @ignore
+ * @internal
+ */
private _revoke: () => void;
private callBackEnabled: boolean = true;
diff --git a/packages/melonjs/src/geometries/path2d.ts b/packages/melonjs/src/geometries/path2d.ts
index 948b829535..c5b69582e5 100644
--- a/packages/melonjs/src/geometries/path2d.ts
+++ b/packages/melonjs/src/geometries/path2d.ts
@@ -66,6 +66,7 @@ class Path2D {
* whether to start fresh or connect from the current point (the native
* Path2D behavior).
* @ignore
+ * @internal
*/
private penMoved = false;
@@ -407,6 +408,7 @@ class Path2D {
* silently start a new sub-path, which fill() treats as a HOLE cut out
* of the shape.
* @ignore
+ * @internal
*/
private connectTo(x: number, y: number) {
if (this.points.length === 0 && !this.penMoved) {
diff --git a/packages/melonjs/src/geometries/polygon.ts b/packages/melonjs/src/geometries/polygon.ts
index a59db7c451..e9e9970f33 100644
--- a/packages/melonjs/src/geometries/polygon.ts
+++ b/packages/melonjs/src/geometries/polygon.ts
@@ -53,12 +53,14 @@ export class Polygon {
* to the position of the `n`th point. If you want to draw an edge normal, you must first
* translate to the position of the starting point.
* @ignore
+ * @internal
*/
normals: Vector2d[];
/**
* The bounding rectangle for this shape
* @ignore
+ * @internal
*/
private _bounds: Bounds;
diff --git a/packages/melonjs/src/geometries/roundrect.ts b/packages/melonjs/src/geometries/roundrect.ts
index 7990024ff0..bad99ca8f4 100644
--- a/packages/melonjs/src/geometries/roundrect.ts
+++ b/packages/melonjs/src/geometries/roundrect.ts
@@ -105,16 +105,22 @@ function updateRoundRectVertices(
export class RoundRect extends Polygon {
/**
* Corner radius.
+ * @ignore
+ * @internal
*/
_radius: number;
/**
* stored width
+ * @ignore
+ * @internal
*/
_width: number;
/**
* stored height
+ * @ignore
+ * @internal
*/
_height: number;
@@ -240,6 +246,7 @@ export class RoundRect extends Polygon {
* Rebuild polygon vertices to approximate the rounded corners.
* Reuses existing Vector2d instances when the vertex count matches.
* @ignore
+ * @internal
*/
_updateVertices() {
const updated = updateRoundRectVertices(
diff --git a/packages/melonjs/src/geometries/sphere.ts b/packages/melonjs/src/geometries/sphere.ts
index 87693fec71..a59efc076e 100644
--- a/packages/melonjs/src/geometries/sphere.ts
+++ b/packages/melonjs/src/geometries/sphere.ts
@@ -32,6 +32,7 @@ export class Sphere {
* {@link Sphere.getBounds} call so a sphere used only for inline
* `overlaps` checks doesn't pay for the AABB.
* @ignore
+ * @internal
*/
_bounds?: AABB3d;
@@ -142,7 +143,10 @@ export class Sphere {
return this._bounds;
}
- /** @ignore */
+ /**
+ * @ignore
+ * @internal
+ */
_updateBounds() {
const r = Math.abs(this.radius);
this._bounds!.setMinMax(
diff --git a/packages/melonjs/src/geometries/toarccanvas.ts b/packages/melonjs/src/geometries/toarccanvas.ts
index af9fb70ba8..0fd2ddc592 100644
--- a/packages/melonjs/src/geometries/toarccanvas.ts
+++ b/packages/melonjs/src/geometries/toarccanvas.ts
@@ -2,6 +2,7 @@ import { degToRad, pow } from "../math/math.ts";
/**
* @ignore
+ * @internal
*/
function correctRadii(
signedRx: number,
@@ -22,6 +23,7 @@ function correctRadii(
/**
* @ignore
+ * @internal
*/
function mat2DotVec2(
[m00, m01, m10, m11]: [number, number, number, number],
@@ -32,6 +34,7 @@ function mat2DotVec2(
/**
* @ignore
+ * @internal
*/
function vec2Add([ux, uy]: [number, number], [vx, vy]: [number, number]) {
return [ux + vx, uy + vy];
@@ -39,6 +42,7 @@ function vec2Add([ux, uy]: [number, number], [vx, vy]: [number, number]) {
/**
* @ignore
+ * @internal
*/
function vec2Scale([a0, a1]: [number, number], scalar: number) {
return [a0 * scalar, a1 * scalar];
@@ -46,6 +50,7 @@ function vec2Scale([a0, a1]: [number, number], scalar: number) {
/**
* @ignore
+ * @internal
*/
function vec2Dot([ux, uy]: [number, number], [vx, vy]: [number, number]) {
return ux * vx + uy * vy;
@@ -53,6 +58,7 @@ function vec2Dot([ux, uy]: [number, number], [vx, vy]: [number, number]) {
/**
* @ignore
+ * @internal
*/
function vec2Mag([ux, uy]: [number, number]) {
return Math.sqrt(ux ** 2 + uy ** 2);
@@ -60,6 +66,7 @@ function vec2Mag([ux, uy]: [number, number]) {
/**
* @ignore
+ * @internal
*/
function vec2Angle(u: [number, number], v: [number, number]) {
const [ux, uy] = u;
diff --git a/packages/melonjs/src/input/gamepad.ts b/packages/melonjs/src/input/gamepad.ts
index f83fef9fc2..3c8c806b71 100644
--- a/packages/melonjs/src/input/gamepad.ts
+++ b/packages/melonjs/src/input/gamepad.ts
@@ -34,10 +34,15 @@ let deadzone = 0.1;
/**
* Normalize axis values for wired Xbox 360
* @ignore
+ * @internal
*/
function wiredXbox360NormalizeFn(
this: any,
value: number,
+ /**
+ * @ignore
+ * @internal
+ */
_axis: number,
button: number,
): number {
@@ -53,6 +58,7 @@ function wiredXbox360NormalizeFn(
/**
* Normalize axis values for OUYA
* @ignore
+ * @internal
*/
function ouyaNormalizeFn(
this: any,
@@ -90,6 +96,7 @@ const leadingZeroRE = /^0+/;
*
* This function normalizes the id to support both formats
* @ignore
+ * @internal
*/
function addMapping(id: string, mapping: Partial): void {
const expanded_id = id.replace(
@@ -188,6 +195,7 @@ const remap: Map = new Map();
/**
* Update gamepad status
* @ignore
+ * @internal
*/
const updateGamepads = function (): void {
const gamepads = navigator.getGamepads();
diff --git a/packages/melonjs/src/input/pointer.ts b/packages/melonjs/src/input/pointer.ts
index a32e863ffd..b667c04788 100644
--- a/packages/melonjs/src/input/pointer.ts
+++ b/packages/melonjs/src/input/pointer.ts
@@ -6,6 +6,7 @@ import { _app, locked } from "./pointerevent.ts";
/**
* a temporary vector object
* @ignore
+ * @internal
*/
const tmpVec = new Vector2d();
@@ -177,6 +178,7 @@ class Pointer extends Bounds {
/**
* @ignore
+ * @internal
*/
constructor(x: number = 0, y: number = 0, w: number = 1, h: number = 1) {
// parent constructor
diff --git a/packages/melonjs/src/input/pointerevent.ts b/packages/melonjs/src/input/pointerevent.ts
index c08a6c8d2e..bed281948e 100644
--- a/packages/melonjs/src/input/pointerevent.ts
+++ b/packages/melonjs/src/input/pointerevent.ts
@@ -26,6 +26,7 @@ interface PointerHandler {
/**
* A pool of `Pointer` objects to cache pointer/touch event coordinates.
* @ignore
+ * @internal
*/
const T_POINTERS: Pointer[] = [];
@@ -38,9 +39,14 @@ let currentPointer: Rect;
/**
* reference to the active application instance
* @ignore
+ * @internal
*/
export let _app: Application;
on(GAME_INIT, (app: Application) => {
+ /**
+ * @ignore
+ * @internal
+ */
_app = app;
});
@@ -112,12 +118,14 @@ const pointerEventMap: Record = {
/**
* Array of normalized events (mouse, touch, pointer)
* @ignore
+ * @internal
*/
const normalizedEvents: Pointer[] = [];
/**
* addEventListerner for the specified event list and callback
* @ignore
+ * @internal
*/
function registerEventListener(
eventList: string[],
@@ -135,6 +143,7 @@ function registerEventListener(
/**
* enable pointer event (Pointer/Mouse/Touch)
* @ignore
+ * @internal
*/
function enablePointerEvent(): void {
if (!pointerInitialized) {
@@ -232,6 +241,7 @@ function enablePointerEvent(): void {
/**
* @ignore
+ * @internal
*/
function findActiveEvent(
activeEventList: string[],
@@ -247,6 +257,7 @@ function findActiveEvent(
/**
* @ignore
+ * @internal
*/
function findAllActiveEvents(
activeEventList: string[],
@@ -265,6 +276,7 @@ function findAllActiveEvents(
/**
* @ignore
+ * @internal
*/
function triggerEvent(
handlers: PointerHandler,
@@ -292,6 +304,7 @@ function triggerEvent(
/**
* propagate events to registered objects
* @ignore
+ * @internal
*/
function dispatchEvent(normalizedEvents: Pointer[]): boolean {
let handled = false;
@@ -501,6 +514,7 @@ function dispatchEvent(normalizedEvents: Pointer[]): boolean {
/**
* translate event coordinates
* @ignore
+ * @internal
*/
function normalizeEvent(originalEvent: any): Pointer[] {
let _pointer: Pointer;
@@ -550,6 +564,7 @@ function normalizeEvent(originalEvent: any): Pointer[] {
/**
* mouse/touch/pointer event management (move)
* @ignore
+ * @internal
*/
function onMoveEvent(e: Event): void {
// dispatch mouse event to registered object
@@ -560,6 +575,7 @@ function onMoveEvent(e: Event): void {
/**
* mouse/touch/pointer event management (start/down, end/up)
* @ignore
+ * @internal
*/
function onPointerEvent(e: Event): void {
// normalize eventTypes
diff --git a/packages/melonjs/src/lang/deprecated.js b/packages/melonjs/src/lang/deprecated.js
index 5d78b32b2b..18eb63d50b 100644
--- a/packages/melonjs/src/lang/deprecated.js
+++ b/packages/melonjs/src/lang/deprecated.js
@@ -36,8 +36,6 @@ export class CanvasTexture extends CanvasRenderTarget {
/**
* set the line width used when stroking shapes
* @public
- * @name setLineWidth
- * @memberof CanvasRenderer#
* @param {number} width - the line width in pixels
* @deprecated since 17.3.0
* @see lineWidth
@@ -50,8 +48,6 @@ CanvasRenderer.prototype.setLineWidth = function (width) {
/**
* set the line width used when stroking shapes
* @public
- * @name setLineWidth
- * @memberof WebGLRenderer#
* @param {number} width - the line width in pixels
* @deprecated since 17.3.0
* @see lineWidth
diff --git a/packages/melonjs/src/level/gltf/GLTFModel.js b/packages/melonjs/src/level/gltf/GLTFModel.js
index 3721ab4cce..a0c59aefe3 100644
--- a/packages/melonjs/src/level/gltf/GLTFModel.js
+++ b/packages/melonjs/src/level/gltf/GLTFModel.js
@@ -31,7 +31,6 @@ const _val = [0, 0, 0, 0];
const _localScratch = new Array(16);
/**
- * @classdesc
* A rig-driven 3D model loaded from an animated glTF/GLB asset. Unlike a static
* {@link GLTFScene} (which flattens each node into an independent {@link Mesh}),
* a `GLTFModel` keeps the node **hierarchy** intact so a parent transform
@@ -68,10 +67,15 @@ export default class GLTFModel extends Container {
* pixels per glTF unit (uniform scene scale)
* @type {number}
* @ignore
+ * @internal
*/
this.scale = options.scale ?? 1;
// right-handed (glTF) → negate Z as well as Y so the Y-up→Y-down bridge
// is a rotation, matching Mesh#rightHanded / GLTFScene
+ /**
+ * @ignore
+ * @internal
+ */
this._zSign = options.rightHanded !== false ? -1 : 1;
// scene meshes carry their own world transform; the GPU depth test
@@ -87,13 +91,29 @@ export default class GLTFModel extends Container {
// entirely (same mechanism Mesh uses on the Camera3d world path).
this.applyAnchorTransform = false;
- /** the node hierarchy keyed by glTF node index @ignore */
+ /**
+ * the node hierarchy keyed by glTF node index
+ * @ignore
+ * @internal
+ */
this._nodes = data.graph.nodes;
- /** root node indices @ignore */
+ /**
+ * root node indices
+ * @ignore
+ * @internal
+ */
this._roots = data.graph.roots;
- /** glTF node index → its part Mesh instances (one per primitive) @ignore */
+ /**
+ * glTF node index → its part Mesh instances (one per primitive)
+ * @ignore
+ * @internal
+ */
this._meshByNode = {};
- /** glTF node index → cached rest (bind-pose) local matrix @ignore */
+ /**
+ * glTF node index → cached rest (bind-pose) local matrix
+ * @ignore
+ * @internal
+ */
this._restMatrix = {};
/**
* glTF node index → its world matrix, a persistent 16-element buffer
@@ -101,6 +121,7 @@ export default class GLTFModel extends Container {
* during the DFS, so each node needs its own). Preallocated here so the
* per-frame pose path allocates nothing.
* @ignore
+ * @internal
*/
this._world = {};
@@ -197,7 +218,11 @@ export default class GLTFModel extends Container {
// index the animation clips, pre-grouping each clip's channels by the
// node they target (so sampling a node is a single map lookup)
- /** name → clip `{ name, duration, channelsByNode, animatedNodes }` @ignore */
+ /**
+ * name → clip `{ name, duration, channelsByNode, animatedNodes }`
+ * @ignore
+ * @internal
+ */
this.anim = {};
for (const clip of data.animations ?? []) {
const channelsByNode = new Map();
@@ -237,11 +262,22 @@ export default class GLTFModel extends Container {
// this.onended;
// current animation state
- /** @ignore */
+ /**
+ * @ignore
+ * @internal
+ */
this.current = { name: undefined, time: 0, length: 0 };
- /** loop-completion callback (built from the options) @ignore */
+ /**
+ * loop-completion callback (built from the options)
+ * @ignore
+ * @internal
+ */
this.resetAnim = undefined;
- /** set when a `loop:false` clip has finished its single cycle @ignore */
+ /**
+ * set when a `loop:false` clip has finished its single cycle
+ * @ignore
+ * @internal
+ */
this._animDone = false;
// pose to the bind/rest pose so the model is correctly assembled even
@@ -447,6 +483,7 @@ export default class GLTFModel extends Container {
* node tree, writing each part mesh's placement. Nodes the current clip does
* not animate use their cached rest matrix.
* @ignore
+ * @internal
*/
/**
* Whether this model is still alive.
@@ -461,12 +498,17 @@ export default class GLTFModel extends Container {
* `pos` and not `ancestor`: a model that was never added to a container is
* perfectly poseable, and several callers do exactly that.
* @ignore
+ * @internal
* @returns {boolean} true while the model can still be posed
*/
_isLive() {
return this.pos !== undefined;
}
+ /**
+ * @ignore
+ * @internal
+ */
_pose() {
const clip = this.current.name ? this.anim[this.current.name] : null;
const t = this.current.time;
@@ -479,6 +521,7 @@ export default class GLTFModel extends Container {
* DFS one node: compose its local matrix, multiply by the parent world,
* apply to its meshes, recurse into children.
* @ignore
+ * @internal
*/
_visit(idx, parentWorld, clip, t) {
const node = this._nodes[idx];
@@ -509,6 +552,7 @@ export default class GLTFModel extends Container {
* otherwise the cached rest matrix.
* @returns {number[]} 16-element column-major matrix
* @ignore
+ * @internal
*/
_localMatrix(idx, clip, t) {
const node = this._nodes[idx];
@@ -556,6 +600,7 @@ export default class GLTFModel extends Container {
* zeroed). Mirrors the static {@link GLTFScene} center-split, recomputed per
* frame.
* @ignore
+ * @internal
*/
_applyWorldToMesh(mesh, world) {
mesh.pos.set(world[12] * this.scale, -world[13] * this.scale);
diff --git a/packages/melonjs/src/level/gltf/GLTFScene.js b/packages/melonjs/src/level/gltf/GLTFScene.js
index 9b670c13fa..3c08b45bea 100644
--- a/packages/melonjs/src/level/gltf/GLTFScene.js
+++ b/packages/melonjs/src/level/gltf/GLTFScene.js
@@ -9,7 +9,6 @@ import GLTFModel from "./GLTFModel.js";
import { linearToSrgb8 } from "./srgb.js";
/**
- * @classdesc
* A loadable 3D scene parsed from a glTF / GLB asset. Instances are created
* and registered with the {@link level} director (usually automatically by
* the preloader), so a glTF scene loads with the same one-call ergonomics as
@@ -279,6 +278,7 @@ export default class GLTFScene {
* @param {number} scale - the scene's world scale (positions/ranges follow it)
* @param {object} options - the `addTo` options (`lights` toggle)
* @ignore
+ * @internal
*/
_addLights(container, zSign, scale, options) {
if (options.lights === false) {
@@ -353,6 +353,7 @@ export default class GLTFScene {
* the meshes and lights are ordinary world children, removed by the
* director's `container.reset()` on the next load.
* @ignore
+ * @internal
*/
destroy() {}
}
@@ -377,6 +378,7 @@ export default class GLTFScene {
* @param {InstancedMesh} mesh - the mesh to fill
* @param {object} instances - `{count, translation, rotation, scale}`
* @ignore
+ * @internal
*/
export function fillInstances(mesh, instances) {
const { count, translation, rotation, scale } = instances;
diff --git a/packages/melonjs/src/level/gltf/gltf_sampler.js b/packages/melonjs/src/level/gltf/gltf_sampler.js
index a29bcc3d03..8e1b1eebfc 100644
--- a/packages/melonjs/src/level/gltf/gltf_sampler.js
+++ b/packages/melonjs/src/level/gltf/gltf_sampler.js
@@ -8,6 +8,7 @@
* 4 for a rotation quaternion) and `interpolation` is `"LINEAR"` | `"STEP"` |
* `"CUBICSPLINE"`.
* @ignore
+ * @internal
*/
// reused result for findKeyframe — the value is consumed immediately by the
@@ -26,6 +27,7 @@ const _kf = { i0: 0, i1: 0, alpha: 0 };
* @param {number} t - sample time (same units as `times`, i.e. seconds)
* @returns {{ i0: number, i1: number, alpha: number }} reused result object
* @ignore
+ * @internal
*/
export function findKeyframe(times, t) {
const n = times.length;
@@ -71,6 +73,7 @@ export function findKeyframe(times, t) {
* @param {number} t - blend factor 0..1
* @param {number[]} out - 4-element [x,y,z,w] result
* @ignore
+ * @internal
*/
export function slerpQuat(values, o0, o1, t, out) {
const ax = values[o0];
@@ -129,6 +132,7 @@ export function slerpQuat(values, o0, o1, t, out) {
* @param {number[]} out - destination, at least `channel.stride` long
* @returns {number[]} `out`
* @ignore
+ * @internal
*/
export function sampleChannel(channel, t, out) {
const { times, values, stride, interpolation } = channel;
diff --git a/packages/melonjs/src/level/level.js b/packages/melonjs/src/level/level.js
index 5612f674ce..c2e597cb30 100644
--- a/packages/melonjs/src/level/level.js
+++ b/packages/melonjs/src/level/level.js
@@ -15,6 +15,7 @@ let currentLevelIdx = 0;
/**
* @ignore
+ * @internal
*/
function safeLoadLevel(levelId, options, restart) {
// clean the destination container
@@ -62,14 +63,13 @@ function safeLoadLevel(levelId, options, restart) {
/**
* Load a TMX level
- * @name loadTMXLevel
- * @memberof level
* @private
* @param {string} levelId - level id
* @param {Container} container - target container
* @param {boolean} [flatten=true] - if true, flatten all objects into the given container
* @param {boolean} [setViewportBounds=false] - if true, set the viewport bounds to the map size, this should be set to true especially if adding a level to the game world container.
* @ignore
+ * @internal
*/
function loadTMXLevel(levelId, container, flatten, setViewportBounds) {
const level = levels[levelId];
@@ -92,8 +92,6 @@ function loadTMXLevel(levelId, container, flatten, setViewportBounds) {
export const level = {
/**
* add a level into the game manager (usually called by the preloader)
- * @name add
- * @memberof level
* @public
* @param {string} format - level format ("tmx" for Tiled maps, "gltf" / "glb" for 3D scenes)
* @param {string} levelId - the level id (or name)
@@ -137,8 +135,6 @@ export const level = {
/**
* load a level into the game manager
* (will also create all level defined entities, etc..)
- * @name load
- * @memberof level
* @public
* @param {string} levelId - level id
* @param {object} [options] - additional optional parameters
@@ -224,8 +220,6 @@ export const level = {
/**
* return the current level id
- * @name getCurrentLevelId
- * @memberof level
* @public
* @returns {string}
*/
@@ -237,8 +231,6 @@ export const level = {
* return the current level definition.
* for a reference to the live instantiated level,
* rather use the container in which it was loaded (e.g. app.world)
- * @name getCurrentLevel
- * @memberof level
* @public
* @returns {TMXTileMap|GLTFScene} the current level object (a TMXTileMap for Tiled maps, a GLTFScene for glTF/GLB scenes)
*/
@@ -248,8 +240,6 @@ export const level = {
/**
* reload the current level
- * @name reload
- * @memberof level
* @public
* @param {object} [options] - additional optional parameters
* @param {Container} [options.container=game.world] - container in which to load the specified level
@@ -265,8 +255,6 @@ export const level = {
/**
* load the next level
- * @name next
- * @memberof level
* @public
* @param {object} [options] - additional optional parameters
* @param {Container} [options.container=game.world] - container in which to load the specified level
@@ -285,8 +273,6 @@ export const level = {
/**
* load the previous level
- * @name previous
- * @memberof level
* @public
* @param {object} [options] - additional optional parameters
* @param {Container} [options.container=game.world] - container in which to load the specified level
@@ -305,8 +291,6 @@ export const level = {
/**
* return the amount of level preloaded
- * @name levelCount
- * @memberof level
* @public
* @returns {number} the amount of level preloaded
*/
diff --git a/packages/melonjs/src/level/tiled/TMXGroup.js b/packages/melonjs/src/level/tiled/TMXGroup.js
index 0aedfa8916..92dc62d09f 100644
--- a/packages/melonjs/src/level/tiled/TMXGroup.js
+++ b/packages/melonjs/src/level/tiled/TMXGroup.js
@@ -7,6 +7,7 @@ import { applyTMXProperties, tiledBlendMode } from "./TMXUtils.js";
* object group definition as defined in Tiled.
* (group definition is translated into the virtual `app.world` using `me.Container`)
* @ignore
+ * @internal
*/
export default class TMXGroup {
constructor(map, data, z) {
@@ -100,6 +101,7 @@ export default class TMXGroup {
/**
* reset function
* @ignore
+ * @internal
*/
destroy() {
// clear all allocated objects
@@ -109,6 +111,7 @@ export default class TMXGroup {
/**
* return the object count
* @ignore
+ * @internal
*/
getObjectCount() {
return this.objects.length;
@@ -117,6 +120,7 @@ export default class TMXGroup {
/**
* returns the object at the specified index
* @ignore
+ * @internal
*/
getObjectByIndex(idx) {
return this.objects[idx];
diff --git a/packages/melonjs/src/level/tiled/TMXLayer.js b/packages/melonjs/src/level/tiled/TMXLayer.js
index ce4d3f6fea..f9032d0736 100644
--- a/packages/melonjs/src/level/tiled/TMXLayer.js
+++ b/packages/melonjs/src/level/tiled/TMXLayer.js
@@ -28,6 +28,7 @@ let _warnedNoGpuTileSupportOnce = false;
* extract a 3-bit flip mask from a raw 32-bit GID (Tiled's flip bits live in
* the upper 3 bits)
* @ignore
+ * @internal
*/
function flipMaskFromGid(gid) {
return (
@@ -40,6 +41,7 @@ function flipMaskFromGid(gid) {
/**
* extract a 3-bit flip mask from a Tile object's boolean flip flags
* @ignore
+ * @internal
*/
function flipMaskFromTile(tile) {
return (
@@ -53,6 +55,7 @@ function flipMaskFromTile(tile) {
* reconstruct a legacy 32-bit GID (with Tiled's high flip bits set) from the
* cleaned GID and a 3-bit flip mask, for passing to the Tile constructor
* @ignore
+ * @internal
*/
function gidWithFlips(gid, flipMask) {
return (
@@ -66,6 +69,7 @@ function gidWithFlips(gid, flipMask) {
/**
* Decode a tiled layer's data blob directly into the typed-array layerData
* @ignore
+ * @internal
*/
function setLayerData(layer, bounds, data) {
let idx = 0;
@@ -267,6 +271,7 @@ export default class TMXLayer extends Renderable {
* repeated user-facing reads.
* @type {Array|null}
* @ignore
+ * @internal
*/
this.cachedTile = null;
@@ -360,6 +365,7 @@ export default class TMXLayer extends Renderable {
* when an auto-eligible mode falls back due to a layer feature the GPU
* path doesn't support (orientation, collection-of-image tileset, etc.).
* @ignore
+ * @internal
*/
_resolveRenderMode() {
const root = this.ancestor?.getRootAncestor?.();
@@ -435,6 +441,7 @@ export default class TMXLayer extends Renderable {
* @param {boolean} gpuAllowed - whether `gpuTilemap` is enabled at the world level
* @returns {{ok: boolean, reason?: string}}
* @ignore
+ * @internal
*/
_checkShaderEligibility(renderer, gpuAllowed) {
if (!gpuAllowed) {
@@ -568,6 +575,10 @@ export default class TMXLayer extends Renderable {
// 0xFFFF. Warn once per layer so a runtime `setTile` with a
// GID >= 65536 doesn't corrupt the cell undetected.
if (cleanGid > 0xffff && !this._truncationWarned) {
+ /**
+ * @ignore
+ * @internal
+ */
this._truncationWarned = true;
console.warn(
"melonJS: setTile received GID " +
@@ -690,6 +701,7 @@ export default class TMXLayer extends Renderable {
/**
* update animations in a tileset layer
* @ignore
+ * @internal
*/
update(dt) {
let result = this.isDirty;
@@ -704,6 +716,7 @@ export default class TMXLayer extends Renderable {
/**
* draw a tileset layer
* @ignore
+ * @internal
*/
draw(renderer, rect) {
// dispatch to the active renderer — picks shader / preRender / perTile
diff --git a/packages/melonjs/src/level/tiled/TMXObject.js b/packages/melonjs/src/level/tiled/TMXObject.js
index 9d2dd7c94d..62a8eeed09 100644
--- a/packages/melonjs/src/level/tiled/TMXObject.js
+++ b/packages/melonjs/src/level/tiled/TMXObject.js
@@ -14,6 +14,7 @@ import { applyTMXProperties } from "./TMXUtils.js";
* @param {object} settings - TMX object settings
* @returns {string} one of "ellipse", "capsule", "point", "polygon", "polyline", "rectangle"
* @ignore
+ * @internal
*/
function detectShape(settings) {
if (typeof settings.ellipse !== "undefined") {
@@ -38,6 +39,7 @@ function detectShape(settings) {
* a TMX Object defintion, as defined in Tiled
* (Object definition is translated into the virtual `app.world` using `me.Renderable`)
* @ignore
+ * @internal
*/
export default class TMXObject {
constructor(map, settings, z) {
@@ -208,6 +210,7 @@ export default class TMXObject {
/**
* set the object image (for Tiled Object)
* @ignore
+ * @internal
*/
setTile(tilesets) {
const tileset = tilesets.getTilesetByGid(this.gid);
@@ -333,6 +336,7 @@ export default class TMXObject {
/**
* getObjectPropertyByName
* @ignore
+ * @internal
*/
getObjectPropertyByName(name) {
return this[name];
diff --git a/packages/melonjs/src/level/tiled/TMXObjectFactory.js b/packages/melonjs/src/level/tiled/TMXObjectFactory.js
index 89a3aa669d..9875e2e716 100644
--- a/packages/melonjs/src/level/tiled/TMXObjectFactory.js
+++ b/packages/melonjs/src/level/tiled/TMXObjectFactory.js
@@ -9,6 +9,7 @@ import TMXLayer from "./TMXLayer.js";
/**
* registry of Tiled object factory functions
* @ignore
+ * @internal
*/
const factories = new Map();
@@ -16,12 +17,14 @@ const factories = new Map();
* tracks class constructors registered via registerTiledObjectClass
* (used to detect duplicate registrations with different constructors)
* @ignore
+ * @internal
*/
const registeredClasses = new Map();
/**
* whether built-in factories have been registered
* @ignore
+ * @internal
*/
let factoriesInitialized = false;
@@ -31,6 +34,7 @@ let factoriesInitialized = false;
* @param {object} settings - TMX object settings
* @returns {Polygon|object[]} shape(s) for the object body
* @ignore
+ * @internal
*/
export function getDefaultShape(settings) {
if (typeof settings.shapes !== "undefined") {
@@ -59,6 +63,7 @@ export function getDefaultShape(settings) {
* @param {object} settings - TMX object settings
* @returns {string} the factory type key
* @ignore
+ * @internal
*/
export function detectObjectType(settings) {
if (settings instanceof TMXLayer) {
@@ -172,6 +177,7 @@ export function registerTiledObjectClass(name, Constructor) {
/**
* pending class registrations queued before initFactories runs
* @ignore
+ * @internal
*/
const pendingClasses = [];
@@ -182,6 +188,7 @@ const pendingClasses = [];
* @param {string} name - the Tiled class or name to match
* @param {Function} Constructor - class constructor with signature (x, y, settings)
* @ignore
+ * @internal
*/
export function registerBuiltinTiledClass(name, Constructor) {
if (factoriesInitialized) {
@@ -196,6 +203,7 @@ export function registerBuiltinTiledClass(name, Constructor) {
* Register built-in factories and apply pending class registrations.
* Called lazily on first createTMXObject call, after all modules are fully loaded.
* @ignore
+ * @internal
*/
function initFactories() {
// only register built-in structural factories if not already overridden
@@ -233,6 +241,7 @@ function initFactories() {
* @param {TMXTileMap} map - the parent tile map
* @returns {Renderable} the instantiated object
* @ignore
+ * @internal
*/
export function createTMXObject(settings, map) {
if (!factoriesInitialized) {
diff --git a/packages/melonjs/src/level/tiled/TMXTile.js b/packages/melonjs/src/level/tiled/TMXTile.js
index 1f9ab6610c..d32393d1db 100644
--- a/packages/melonjs/src/level/tiled/TMXTile.js
+++ b/packages/melonjs/src/level/tiled/TMXTile.js
@@ -30,6 +30,7 @@ const FLIP_AD_BIT = 1 << 2;
* @param {number} height - tile height in pixels
* @returns {Matrix2d} the same matrix, for chaining
* @ignore
+ * @internal
*/
export function buildFlipTransform(transform, flipMask, width, height) {
const halfW = width / 2;
@@ -92,6 +93,7 @@ export default class Tile extends Bounds {
* the tile transformation matrix (if flipped)
* @type {Matrix2d|null}
* @ignore
+ * @internal
*/
this.currentTransform = null;
@@ -151,6 +153,7 @@ export default class Tile extends Bounds {
* set the transformation matrix for this tile
* @param {Matrix2d} transform - the transformation matrix to apply
* @ignore
+ * @internal
*/
setTileTransform(transform) {
const halfW = this.width / 2;
diff --git a/packages/melonjs/src/level/tiled/TMXTileMap.js b/packages/melonjs/src/level/tiled/TMXTileMap.js
index 02435a7eb7..18c7598633 100644
--- a/packages/melonjs/src/level/tiled/TMXTileMap.js
+++ b/packages/melonjs/src/level/tiled/TMXTileMap.js
@@ -24,6 +24,7 @@ import {
/**
* read the layer Data
* @ignore
+ * @internal
*/
function readLayer(map, data, z) {
return new TMXLayer(
@@ -40,6 +41,7 @@ function readLayer(map, data, z) {
/**
* read the Image Layer Data
* @ignore
+ * @internal
*/
function readImageLayer(map, data, z) {
// resolve embedded JSON image data if present
@@ -102,6 +104,7 @@ function readImageLayer(map, data, z) {
/**
* read the tileset Data
* @ignore
+ * @internal
*/
function readTileset(data, mapTilewidth, mapTileheight) {
return new TMXTileset(data, mapTilewidth, mapTileheight);
@@ -110,6 +113,7 @@ function readTileset(data, mapTilewidth, mapTileheight) {
/**
* read the object group Data
* @ignore
+ * @internal
*/
function readObjectGroup(map, data, z) {
return new TMXGroup(map, data, z);
@@ -122,6 +126,7 @@ function readObjectGroup(map, data, z) {
* those caches are stale until each child happens to call updateBounds on
* its own (which only happens organically when its own pos changes).
* @ignore
+ * @internal
*/
function refreshAbsoluteBounds(container) {
container.forEach((child) => {
@@ -151,6 +156,7 @@ export default class TMXTileMap {
/**
* the level data (JSON)
* @ignore
+ * @internal
*/
this.data = data;
@@ -328,6 +334,7 @@ export default class TMXTileMap {
/**
* parse the map
* @ignore
+ * @internal
*/
readMapObjects(data) {
if (this.initialized === true) {
@@ -435,6 +442,7 @@ export default class TMXTileMap {
/**
* callback funtion for the viewport resize event
* @ignore
+ * @internal
*/
if (setViewportBounds === true) {
const app = container.getRootAncestor().app;
diff --git a/packages/melonjs/src/level/tiled/TMXTileset.js b/packages/melonjs/src/level/tiled/TMXTileset.js
index 1bea6967e3..283d805b4a 100644
--- a/packages/melonjs/src/level/tiled/TMXTileset.js
+++ b/packages/melonjs/src/level/tiled/TMXTileset.js
@@ -27,6 +27,7 @@ export default class TMXTileset {
* per-tile properties indexed by gid
* @type {Map}
* @ignore
+ * @internal
*/
this.tileProperties = new Map();
@@ -34,6 +35,7 @@ export default class TMXTileset {
* per-tile images for "Collection of Image" tilesets, indexed by gid
* @type {Map}
* @ignore
+ * @internal
*/
this.imageCollection = new Map();
@@ -136,6 +138,7 @@ export default class TMXTileset {
* the map's tile grid width (used for tilerendersize="grid")
* @type {number}
* @ignore
+ * @internal
*/
this.mapTilewidth = mapTilewidth ?? this.tilewidth;
@@ -143,19 +146,46 @@ export default class TMXTileset {
* the map's tile grid height (used for tilerendersize="grid")
* @type {number}
* @ignore
+ * @internal
*/
this.mapTileheight = mapTileheight ?? this.tileheight;
/**
* precomputed render scale for tilerendersize="grid" (spritesheet only)
* @private
+ * @ignore
+ * @internal
*/
this._renderScaleX = 1;
+ /**
+ * @ignore
+ * @internal
+ */
this._renderScaleY = 1;
+ /**
+ * @ignore
+ * @internal
+ */
this._renderDw = this.tilewidth;
+ /**
+ * @ignore
+ * @internal
+ */
this._renderDh = this.tileheight;
+ /**
+ * @ignore
+ * @internal
+ */
this._renderDyOffset = 0;
+ /**
+ * @ignore
+ * @internal
+ */
this._renderDxCenter = 0;
+ /**
+ * @ignore
+ * @internal
+ */
this._renderDyCenter = 0;
if (this.tilerendersize === "grid") {
@@ -182,6 +212,7 @@ export default class TMXTileset {
* per-tile sub-rectangles (Tiled 1.9+), indexed by local tile id
* @type {Map}
* @ignore
+ * @internal
*/
this.tileSubRects = new Map();
@@ -195,6 +226,8 @@ export default class TMXTileset {
/**
* Remember the last update timestamp to prevent too many animation updates
* @private
+ * @ignore
+ * @internal
*/
this._lastUpdate = 0;
@@ -244,6 +277,7 @@ export default class TMXTileset {
* non-forward direction (Tiled animations are forward-only) and non-zero
* repeat counts (Tiled animations loop forever).
* @ignore
+ * @internal
*/
_applyAsepriteFrameTags(tileset) {
// getJSON is a direct key lookup (no basename normalization, unlike
@@ -315,6 +349,7 @@ export default class TMXTileset {
* Parse individual tile entries for animations, properties, and images.
* @param {object[]|object} [tiles] - tile entries (array in JSON, object in XML)
* @ignore
+ * @internal
*/
_parseTiles(tiles) {
if (!tiles) {
@@ -426,6 +461,7 @@ export default class TMXTileset {
* Initialize the texture atlas for a spritesheet tileset.
* @param {object} tileset - tileset data
* @ignore
+ * @internal
*/
_initAtlas(tileset) {
// get the global tileset texture
@@ -482,6 +518,7 @@ export default class TMXTileset {
* @param {number} gid - global tile ID
* @param {object} prop - property object
* @ignore
+ * @internal
*/
setTileProperty(gid, prop) {
this.tileProperties.set(gid, prop);
@@ -527,6 +564,7 @@ export default class TMXTileset {
* @param {number} dt - time delta in milliseconds
* @returns {boolean} true if any animation frame changed
* @ignore
+ * @internal
*/
update(dt) {
const now = timer.getTime();
@@ -558,6 +596,7 @@ export default class TMXTileset {
* @param {number} dy - destination y position
* @param {Tile} tmxTile - the tile object to draw
* @ignore
+ * @internal
*/
drawTile(renderer, dx, dy, tmxTile) {
let dw, dh;
@@ -656,6 +695,7 @@ export default class TMXTileset {
* @param {number} gid - the tile's global id (with flip bits already stripped)
* @param {number} flipMask - 3-bit packed flip mask (H=1, V=2, AD=4)
* @ignore
+ * @internal
*/
drawTileRaw(renderer, dx, dy, gid, flipMask) {
let dw, dh;
diff --git a/packages/melonjs/src/level/tiled/TMXTilesetGroup.js b/packages/melonjs/src/level/tiled/TMXTilesetGroup.js
index d2072eb618..d028741456 100644
--- a/packages/melonjs/src/level/tiled/TMXTilesetGroup.js
+++ b/packages/melonjs/src/level/tiled/TMXTilesetGroup.js
@@ -8,6 +8,10 @@ export default class TMXTilesetGroup {
this.tilesets = [];
this.length = 0;
// cache last matched tileset — consecutive tiles usually share the same tileset
+ /**
+ * @ignore
+ * @internal
+ */
this._lastTileset = null;
}
diff --git a/packages/melonjs/src/level/tiled/TMXUtils.js b/packages/melonjs/src/level/tiled/TMXUtils.js
index 4c67bbcfea..cdfc016f8a 100644
--- a/packages/melonjs/src/level/tiled/TMXUtils.js
+++ b/packages/melonjs/src/level/tiled/TMXUtils.js
@@ -11,6 +11,7 @@ let embeddedImageId = 0;
* a generated filename (with extension) suitable for getImage().
* Works for both XML-parsed data (base64 string) and JSON data.
* @ignore
+ * @internal
* @param {string} base64 - raw base64-encoded image data
* @param {string} [format="png"] - image format
* @param {number} [width] - image width hint
@@ -27,6 +28,7 @@ export function cacheEmbeddedImage(base64, format = "png", width, height) {
* If the given data object has an embedded base64 image (JSON `imagedata`
* property), decode it, cache it, and replace with a generated filename.
* @ignore
+ * @internal
* @param {object} data - tileset, tile, or layer data
*/
export function resolveEmbeddedImage(data) {
@@ -64,6 +66,7 @@ export function tiledBlendMode(mode) {
/**
* Apply an opacity multiplier to a renderable and its child renderable (if any).
* @ignore
+ * @internal
* @param {Renderable} obj - the renderable to apply to
* @param {number} opacity - the opacity multiplier
*/
@@ -81,6 +84,7 @@ export function applyObjectOpacity(obj, opacity) {
* Propagate a blend mode to a renderable and its child renderable (if any).
* Only applies when the object still has the default "normal" blend mode.
* @ignore
+ * @internal
* @param {Renderable} obj - the renderable to apply to
* @param {string} blendMode - the blend mode to propagate
*/
@@ -104,6 +108,7 @@ export function propagateBlendMode(obj, blendMode) {
/**
* Parse a Tiled tint color hex string into a melonJS Color object.
* @ignore
+ * @internal
* @param {string} tintcolor - hex color string from Tiled (e.g. "#ff0000")
* @returns {Color|undefined} parsed Color, or undefined if no tint
*/
@@ -124,6 +129,7 @@ const LONG_ARGB = /^#([\da-fA-F]{2})([\da-fA-F]{6})$/;
* Handles int, float, bool, json:, eval:, #ARGB colors,
* and auto-detection for untyped properties.
* @ignore
+ * @internal
* @param {string} name - property name (used for ratio/anchorPoint normalization)
* @param {string} type - declared Tiled type ("int","float","bool","string", etc.)
* @param {*} raw - raw value (string from XML, or already-typed from JSON)
@@ -231,6 +237,7 @@ function coerceTMXValue(name, type, raw) {
* Moves source → image, width → imagewidth, height → imageheight.
* For embedded images (no source, has data), decodes and caches the image.
* @ignore
+ * @internal
*/
function flattenImage(obj) {
if (obj.image) {
@@ -257,6 +264,7 @@ function flattenImage(obj) {
/**
* Normalizer callback for xmlToObject — converts TMX XML into Tiled JSON format.
* @ignore
+ * @internal
*/
function normalizeTMX(obj, item, parse) {
const nodeName = item.nodeName;
@@ -427,7 +435,6 @@ export { decode, setInflateFunction } from "../../utils/decode.ts";
/**
* Parse a XML TMX object and returns the corresponding javascript object
- * @memberof TMXUtils
* @param {Document} xml - XML TMX object
* @returns {object} Javascript object
*/
@@ -437,7 +444,6 @@ export function parse(xml) {
/**
* Apply TMX Properties to the given object
- * @memberof TMXUtils
* @param {object} obj - object to apply the properties to
* @param {object} data - TMX data object
*/
diff --git a/packages/melonjs/src/level/tiled/factories/shape.js b/packages/melonjs/src/level/tiled/factories/shape.js
index e829aea626..a4e59ac473 100644
--- a/packages/melonjs/src/level/tiled/factories/shape.js
+++ b/packages/melonjs/src/level/tiled/factories/shape.js
@@ -7,6 +7,7 @@ import { getDefaultShape } from "../TMXObjectFactory.js";
* @param {object} settings - TMX object settings
* @returns {Renderable} the created shape object
* @ignore
+ * @internal
*/
export function createShapeObject(settings) {
const obj = new Renderable(
diff --git a/packages/melonjs/src/level/tiled/factories/text.js b/packages/melonjs/src/level/tiled/factories/text.js
index 481da98303..aa182fb768 100644
--- a/packages/melonjs/src/level/tiled/factories/text.js
+++ b/packages/melonjs/src/level/tiled/factories/text.js
@@ -6,6 +6,7 @@ import Text from "../../../renderable/text/text.js";
* @param {object} settings - TMX object settings
* @returns {Renderable} the created text object
* @ignore
+ * @internal
*/
export function createTextObject(settings) {
if (typeof settings.text.anchorPoint === "undefined") {
diff --git a/packages/melonjs/src/level/tiled/factories/tile.js b/packages/melonjs/src/level/tiled/factories/tile.js
index e7778b43ed..29a04c20a0 100644
--- a/packages/melonjs/src/level/tiled/factories/tile.js
+++ b/packages/melonjs/src/level/tiled/factories/tile.js
@@ -5,6 +5,7 @@ import { getDefaultShape } from "../TMXObjectFactory.js";
* @param {object} settings - TMX object settings
* @returns {Renderable} the created tile object
* @ignore
+ * @internal
*/
export function createTileObject(settings) {
const shape = getDefaultShape(settings);
diff --git a/packages/melonjs/src/level/tiled/renderer/TMXHexagonalRenderer.js b/packages/melonjs/src/level/tiled/renderer/TMXHexagonalRenderer.js
index 911b270c03..b8046168f2 100644
--- a/packages/melonjs/src/level/tiled/renderer/TMXHexagonalRenderer.js
+++ b/packages/melonjs/src/level/tiled/renderer/TMXHexagonalRenderer.js
@@ -60,6 +60,7 @@ export default class TMXHexagonalRenderer extends TMXRenderer {
/**
* return true if the renderer can render the specified layer
* @ignore
+ * @internal
*/
canRender(layer) {
return layer.orientation === "hexagonal" && super.canRender(layer);
@@ -68,6 +69,7 @@ export default class TMXHexagonalRenderer extends TMXRenderer {
/**
* return the bounding rect for this map renderer
* @ignore
+ * @internal
*/
getBounds(layer) {
const bounds = layer instanceof TMXLayer ? boundsPool.get() : this.bounds;
@@ -99,6 +101,7 @@ export default class TMXHexagonalRenderer extends TMXRenderer {
/**
* @ignore
+ * @internal
*/
doStaggerX(x) {
return this.staggerX && (x & 1) ^ this.staggerEven;
@@ -106,6 +109,7 @@ export default class TMXHexagonalRenderer extends TMXRenderer {
/**
* @ignore
+ * @internal
*/
doStaggerY(y) {
return !this.staggerX && (y & 1) ^ this.staggerEven;
@@ -113,6 +117,7 @@ export default class TMXHexagonalRenderer extends TMXRenderer {
/**
* @ignore
+ * @internal
*/
topLeft(x, y, v) {
const ret = v || vector2dPool.get();
@@ -135,6 +140,7 @@ export default class TMXHexagonalRenderer extends TMXRenderer {
/**
* @ignore
+ * @internal
*/
topRight(x, y, v) {
const ret = v || vector2dPool.get();
@@ -157,6 +163,7 @@ export default class TMXHexagonalRenderer extends TMXRenderer {
/**
* @ignore
+ * @internal
*/
bottomLeft(x, y, v) {
const ret = v || vector2dPool.get();
@@ -179,6 +186,7 @@ export default class TMXHexagonalRenderer extends TMXRenderer {
/**
* @ignore
+ * @internal
*/
bottomRight(x, y, v) {
const ret = v || vector2dPool.get();
@@ -202,6 +210,7 @@ export default class TMXHexagonalRenderer extends TMXRenderer {
/**
* return the tile position corresponding to the specified pixel
* @ignore
+ * @internal
*/
pixelToTileCoords(x, y, v) {
const ret = v || vector2dPool.get();
@@ -293,6 +302,7 @@ export default class TMXHexagonalRenderer extends TMXRenderer {
/**
* return the pixel position corresponding of the specified tile
* @ignore
+ * @internal
*/
tileToPixelCoords(x, y, v) {
const tileX = Math.floor(x);
@@ -319,6 +329,7 @@ export default class TMXHexagonalRenderer extends TMXRenderer {
/**
* draw the tile map (legacy entry point — accepts a fully-constructed Tile)
* @ignore
+ * @internal
*/
drawTile(renderer, x, y, tmxTile) {
const tileset = tmxTile.tileset;
@@ -339,6 +350,7 @@ export default class TMXHexagonalRenderer extends TMXRenderer {
* draw a tile from raw (gid, flipMask, tileset) data — used by the hot
* rendering loop to bypass Tile construction
* @ignore
+ * @internal
*/
drawTileRaw(renderer, x, y, gid, flipMask, tileset) {
const point = this.tileToPixelCoords(x, y, vector2dPool.get());
@@ -357,6 +369,7 @@ export default class TMXHexagonalRenderer extends TMXRenderer {
/**
* draw the tile map
* @ignore
+ * @internal
*/
drawTileLayer(renderer, layer, rect) {
// get top-left and bottom-right tile position
diff --git a/packages/melonjs/src/level/tiled/renderer/TMXIsometricRenderer.js b/packages/melonjs/src/level/tiled/renderer/TMXIsometricRenderer.js
index d1fc2add60..dda927ffd4 100644
--- a/packages/melonjs/src/level/tiled/renderer/TMXIsometricRenderer.js
+++ b/packages/melonjs/src/level/tiled/renderer/TMXIsometricRenderer.js
@@ -22,6 +22,7 @@ export default class TMXIsometricRenderer extends TMXRenderer {
/**
* return true if the renderer can render the specified layer
* @ignore
+ * @internal
*/
canRender(layer) {
return layer.orientation === "isometric" && super.canRender(layer);
@@ -30,6 +31,7 @@ export default class TMXIsometricRenderer extends TMXRenderer {
/**
* return the bounding rect for this map renderer
* @ignore
+ * @internal
*/
getBounds(layer) {
const bounds = layer instanceof TMXLayer ? boundsPool.get() : this.bounds;
@@ -45,6 +47,7 @@ export default class TMXIsometricRenderer extends TMXRenderer {
/**
* return the tile position corresponding to the specified pixel
* @ignore
+ * @internal
*/
pixelToTileCoords(x, y, v) {
const ret = v || vector2dPool.get();
@@ -57,6 +60,7 @@ export default class TMXIsometricRenderer extends TMXRenderer {
/**
* return the pixel position corresponding of the specified tile
* @ignore
+ * @internal
*/
tileToPixelCoords(x, y, v) {
const ret = v || vector2dPool.get();
@@ -70,6 +74,7 @@ export default class TMXIsometricRenderer extends TMXRenderer {
* fix the position of Objects to match
* the way Tiled places them
* @ignore
+ * @internal
*/
adjustPosition(obj) {
const tileX = obj.x / this.hTilewidth;
@@ -87,6 +92,7 @@ export default class TMXIsometricRenderer extends TMXRenderer {
/**
* draw the tile map (legacy entry point — accepts a fully-constructed Tile)
* @ignore
+ * @internal
*/
drawTile(renderer, x, y, tmxTile) {
const tileset = tmxTile.tileset;
@@ -103,6 +109,7 @@ export default class TMXIsometricRenderer extends TMXRenderer {
* draw a tile from raw (gid, flipMask, tileset) data — used by the hot
* rendering loop to bypass Tile construction
* @ignore
+ * @internal
*/
drawTileRaw(renderer, x, y, gid, flipMask, tileset) {
tileset.drawTileRaw(
@@ -117,6 +124,7 @@ export default class TMXIsometricRenderer extends TMXRenderer {
/**
* draw the tile map
* @ignore
+ * @internal
*/
drawTileLayer(renderer, layer, rect) {
// cache a couple of useful references
diff --git a/packages/melonjs/src/level/tiled/renderer/TMXObliqueRenderer.js b/packages/melonjs/src/level/tiled/renderer/TMXObliqueRenderer.js
index ce4a87148f..82c67ab861 100644
--- a/packages/melonjs/src/level/tiled/renderer/TMXObliqueRenderer.js
+++ b/packages/melonjs/src/level/tiled/renderer/TMXObliqueRenderer.js
@@ -43,6 +43,8 @@ export default class TMXObliqueRenderer extends TMXOrthogonalRenderer {
/**
* determinant of the shear matrix (for inverse transform)
* @type {number}
+ * @ignore
+ * @internal
*/
this._det = 1 - this.shearX * this.shearY;
}
@@ -50,6 +52,7 @@ export default class TMXObliqueRenderer extends TMXOrthogonalRenderer {
/**
* return true if the renderer can render the specified layer
* @ignore
+ * @internal
*/
canRender(layer) {
return (
@@ -88,6 +91,7 @@ export default class TMXObliqueRenderer extends TMXOrthogonalRenderer {
/**
* return the tile position corresponding to the specified pixel
* @ignore
+ * @internal
*/
pixelToTileCoords(x, y, v) {
const ret = v || vector2dPool.get();
@@ -100,6 +104,7 @@ export default class TMXObliqueRenderer extends TMXOrthogonalRenderer {
/**
* return the pixel position corresponding of the specified tile
* @ignore
+ * @internal
*/
tileToPixelCoords(x, y, v) {
const ret = v || vector2dPool.get();
@@ -112,6 +117,7 @@ export default class TMXObliqueRenderer extends TMXOrthogonalRenderer {
/**
* draw the tile map (legacy entry point — accepts a fully-constructed Tile)
* @ignore
+ * @internal
*/
drawTile(renderer, x, y, tmxTile) {
const tileset = tmxTile.tileset;
@@ -129,6 +135,7 @@ export default class TMXObliqueRenderer extends TMXOrthogonalRenderer {
* draw a tile from raw (gid, flipMask, tileset) data — used by the hot
* rendering loop to bypass Tile construction
* @ignore
+ * @internal
*/
drawTileRaw(renderer, x, y, gid, flipMask, tileset) {
const dx = tileset.tileoffset.x + x * this.tilewidth + this.skewX * y;
@@ -143,6 +150,7 @@ export default class TMXObliqueRenderer extends TMXOrthogonalRenderer {
/**
* draw the given TMX Layer for the given area
* @ignore
+ * @internal
*/
drawTileLayer(renderer, layer, rect) {
let incX = 1;
diff --git a/packages/melonjs/src/level/tiled/renderer/TMXOrthogonalRenderer.js b/packages/melonjs/src/level/tiled/renderer/TMXOrthogonalRenderer.js
index a516805c19..682b8fddf9 100644
--- a/packages/melonjs/src/level/tiled/renderer/TMXOrthogonalRenderer.js
+++ b/packages/melonjs/src/level/tiled/renderer/TMXOrthogonalRenderer.js
@@ -16,6 +16,7 @@ export default class TMXOrthogonalRenderer extends TMXRenderer {
/**
* return true if the renderer can render the specified layer
* @ignore
+ * @internal
*/
canRender(layer) {
return layer.orientation === "orthogonal" && super.canRender(layer);
@@ -24,6 +25,7 @@ export default class TMXOrthogonalRenderer extends TMXRenderer {
/**
* return the tile position corresponding to the specified pixel
* @ignore
+ * @internal
*/
pixelToTileCoords(x, y, v) {
const ret = v || vector2dPool.get();
@@ -33,6 +35,7 @@ export default class TMXOrthogonalRenderer extends TMXRenderer {
/**
* return the pixel position corresponding of the specified tile
* @ignore
+ * @internal
*/
tileToPixelCoords(x, y, v) {
const ret = v || vector2dPool.get();
@@ -42,6 +45,7 @@ export default class TMXOrthogonalRenderer extends TMXRenderer {
/**
* draw the tile map (legacy entry point — accepts a fully-constructed Tile)
* @ignore
+ * @internal
*/
drawTile(renderer, x, y, tmxTile) {
const tileset = tmxTile.tileset;
@@ -58,6 +62,7 @@ export default class TMXOrthogonalRenderer extends TMXRenderer {
* draw a tile from raw (gid, flipMask, tileset) data — used by the hot
* rendering loop to bypass Tile construction
* @ignore
+ * @internal
*/
drawTileRaw(renderer, x, y, gid, flipMask, tileset) {
tileset.drawTileRaw(
@@ -72,6 +77,7 @@ export default class TMXOrthogonalRenderer extends TMXRenderer {
/**
* draw the tile map
* @ignore
+ * @internal
*/
drawTileLayer(renderer, layer, rect) {
let incX = 1;
diff --git a/packages/melonjs/src/level/tiled/renderer/TMXRenderer.js b/packages/melonjs/src/level/tiled/renderer/TMXRenderer.js
index a3f0331389..a389ec17db 100644
--- a/packages/melonjs/src/level/tiled/renderer/TMXRenderer.js
+++ b/packages/melonjs/src/level/tiled/renderer/TMXRenderer.js
@@ -97,7 +97,8 @@ export default class TMXRenderer {
* @param {number} y - Y coordinate where to draw the tile
* @param {Tile} tile - the tile object to draw
*/
- drawTile() {}
+ // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
+ drawTile(renderer, x, y, tile) {}
/**
* draw the given TMX Layer for the given area
@@ -105,5 +106,6 @@ export default class TMXRenderer {
* @param {TMXLayer} layer - a TMX Layer object
* @param {Rect} rect - the area of the layer to draw
*/
- drawTileLayer() {}
+ // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
+ drawTileLayer(renderer, layer, rect) {}
}
diff --git a/packages/melonjs/src/level/tiled/renderer/TMXStaggeredRenderer.js b/packages/melonjs/src/level/tiled/renderer/TMXStaggeredRenderer.js
index 637cf5674e..20e1e41944 100644
--- a/packages/melonjs/src/level/tiled/renderer/TMXStaggeredRenderer.js
+++ b/packages/melonjs/src/level/tiled/renderer/TMXStaggeredRenderer.js
@@ -10,6 +10,7 @@ export default class TMXStaggeredRenderer extends TMXHexagonalRenderer {
/**
* return true if the renderer can render the specified layer
* @ignore
+ * @internal
*/
canRender(layer) {
return layer.orientation === "staggered" && super.canRender(layer);
@@ -18,6 +19,7 @@ export default class TMXStaggeredRenderer extends TMXHexagonalRenderer {
/**
* return the tile position corresponding to the specified pixel
* @ignore
+ * @internal
*/
pixelToTileCoords(x, y, v) {
let ret = v || vector2dPool.get();
diff --git a/packages/melonjs/src/level/tiled/renderer/autodetect.js b/packages/melonjs/src/level/tiled/renderer/autodetect.js
index e84ebb9b02..2f8c73338b 100644
--- a/packages/melonjs/src/level/tiled/renderer/autodetect.js
+++ b/packages/melonjs/src/level/tiled/renderer/autodetect.js
@@ -8,6 +8,7 @@ import TMXStaggeredRenderer from "./TMXStaggeredRenderer.js";
* return a compatible renderer object for the given map
* @param {TMXTileMap} map
* @ignore
+ * @internal
*/
export function getNewTMXRenderer(map) {
switch (map.orientation) {
diff --git a/packages/melonjs/src/lighting/light2d.ts b/packages/melonjs/src/lighting/light2d.ts
index fe79864fbe..99d4651a3d 100644
--- a/packages/melonjs/src/lighting/light2d.ts
+++ b/packages/melonjs/src/lighting/light2d.ts
@@ -50,6 +50,7 @@ export default class Light2d extends Renderable {
* the world-space geometry of the light's visible area, rewritten each
* frame by {@link Light2d#getVisibleArea} from transform-aware bounds.
* @ignore
+ * @internal
*/
visibleArea: Ellipse;
@@ -260,6 +261,7 @@ export default class Light2d extends Renderable {
* overlay cutouts; rendering the light itself is handled normally as
* part of the world tree walk.
* @ignore
+ * @internal
*/
override onActivateEvent() {
state.current()?._registerLight(this);
@@ -269,6 +271,7 @@ export default class Light2d extends Renderable {
* Auto-deregister this light from the active Stage's lighting set when
* removed from a container.
* @ignore
+ * @internal
*/
override onDeactivateEvent() {
state.current()?._unregisterLight(this);
@@ -277,6 +280,7 @@ export default class Light2d extends Renderable {
/**
* Destroy function
* @ignore
+ * @internal
*/
override destroy() {
colorPool.release(this.color);
diff --git a/packages/melonjs/src/lighting/light3d.ts b/packages/melonjs/src/lighting/light3d.ts
index 2577427bb2..5793fe683c 100644
--- a/packages/melonjs/src/lighting/light3d.ts
+++ b/packages/melonjs/src/lighting/light3d.ts
@@ -172,6 +172,7 @@ export class Light3d extends Renderable {
* Register with the active stage's 3D-light set on activation (when added to
* a rooted container), mirroring {@link Light2d}.
* @ignore
+ * @internal
*/
override onActivateEvent() {
state.current()?._registerLight3d(this);
@@ -180,6 +181,7 @@ export class Light3d extends Renderable {
/**
* Deregister from the active stage when removed from the world.
* @ignore
+ * @internal
*/
override onDeactivateEvent() {
state.current()?._unregisterLight3d(this);
@@ -188,6 +190,7 @@ export class Light3d extends Renderable {
/**
* A light has no visual representation.
* @ignore
+ * @internal
*/
override draw() {}
}
diff --git a/packages/melonjs/src/loader/loader.js b/packages/melonjs/src/loader/loader.js
index 0487481537..d241dd311f 100644
--- a/packages/melonjs/src/loader/loader.js
+++ b/packages/melonjs/src/loader/loader.js
@@ -52,8 +52,6 @@ export const baseURL = {};
* The "anonymous" keyword means that there will be no exchange of user credentials via cookies,
* client-side SSL certificates or HTTP authentication as described in the Terminology section of the CORS specification.
* @type {string}
- * @name crossOrigin
- * @memberof loader
* @default undefined
* @see {@link setOptions}
* @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes}
@@ -74,10 +72,8 @@ export let crossOrigin;
* authorization headers or TLS client certificates. Setting withCredentials has no effect on same-site requests.
* @public
* @type {boolean}
- * @name withCredentials
* @see {@link setOptions}
* @default false
- * @memberof loader
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials}
* @deprecated since 20.4.0, read-only — set it with
* {@link setOptions}. This is a module binding, so assigning to it throws a
@@ -94,6 +90,7 @@ export let withCredentials = false;
/**
* enable the nocache mechanism
* @ignore
+ * @internal
*/
export function setNocache(enable = false) {
nocache = enable ? "?" + ~~(Math.random() * 10000000) : "";
@@ -101,7 +98,6 @@ export function setNocache(enable = false) {
/**
* Sets the options for the loader.
- * @memberof loader
* @param {Object} options - The options to set.
* @param {string} [options.crossOrigin] - The crossOrigin attribute to configure the CORS requests for Image and Video data element.
* @param {boolean} [options.nocache] - Enable or disable the nocache mechanism.
@@ -132,8 +128,6 @@ export function setOptions(options) {
/**
* change the default baseURL for the given asset type.
* (this will prepend the asset URL and must finish with a '/')
- * @name setBaseURL
- * @memberof loader
* @public
* @param {string} type - "*", "audio", "video", "binary", "image", "json", "js", "tmx", "tsx", "fontface", "aseprite", "shader", "obj", "mtl", "gltf", "glb"
* @param {string} [url="./"] - default base URL
@@ -176,6 +170,7 @@ export function setBaseURL(type, url = "./") {
* as the settable option it was documented to be. Use the `onloadcb` parameter
* of {@link loader.preload}, or the {@link event.LOADER_COMPLETE} event.
* @ignore
+ * @internal
*/
let onload;
@@ -201,6 +196,7 @@ const failureLoadedAssets = {};
/**
* init all supported parsers
* @ignore
+ * @internal
*/
function initParsers() {
setParser("binary", preloadBinary);
@@ -225,6 +221,7 @@ function initParsers() {
* Complete loading: invoke the callback and emit the LOADER_COMPLETE event.
* @param {Function} onloadcb - the completion callback
* @ignore
+ * @internal
*/
function completeLoading(onloadcb) {
const callback = onloadcb || onload;
@@ -240,6 +237,7 @@ function completeLoading(onloadcb) {
/**
* just increment the number of already loaded resources
* @ignore
+ * @internal
*/
function onResourceLoaded(res) {
delete failureLoadedAssets[res.src];
@@ -256,6 +254,7 @@ function onResourceLoaded(res) {
* on error callback for image loading
* @param {Asset} asset - asset that loaded with failure
* @ignore
+ * @internal
*/
function onLoadingError(res) {
failureLoadedAssets[res.src] = res;
@@ -266,7 +265,6 @@ function onLoadingError(res) {
/**
* an asset definition to be used with the loader
* @typedef {object} Asset
- * @memberof loader
* @property {string} name - name of the asset
* @property {string} type - the type of the asset ("audio"|"binary"|"image"|"json"|"js"|"tmx"|"tsx"|"fontface"|"video"|"aseprite"|"shader"|"obj"|"mtl"|"gltf"|"glb"). JSON-serialised Tiled maps and tilesets (`.tmj` / `.tsj`) load under `"tmx"` / `"tsx"` — those are file extensions, not asset types.
* @property {string|string[]} [src] - path and/or file name of the resource (for audio assets only the path is required).
@@ -321,7 +319,6 @@ function onLoadingError(res) {
/**
* specify a parser/preload function for the given asset type
- * @memberof loader
* @param {string} type - asset type
* @param {function} parserFn - parser function
* @see {@link Asset.type}
@@ -355,7 +352,6 @@ export function setParser(type, parserFn) {
/**
* set all the specified game assets to be preloaded.
- * @memberof loader
* @param {Asset[]} assets - list of assets to load
* @param {Function} [onloadcb=loader.onload] - function to be called when all resources are loaded
* @param {boolean} [switchToLoadState=true] - automatically switch to the loading screen
@@ -447,7 +443,6 @@ export function preload(assets, onloadcb, switchToLoadState = true) {
/**
* retry loading assets after a loading failure
- * @memberof loader
* @param {string} src - src of asset to reload
* @example
* event.on(
@@ -489,7 +484,6 @@ export function reload(src) {
/**
* Load a single asset (to be used if you need to load additional asset(s) during the game)
- * @memberof loader
* @param {Asset} asset
* @param {Function} [onload] - function to be called when the asset is loaded
* @param {Function} [onerror] - function to be called in case of error
@@ -598,7 +592,6 @@ export function load(asset, onload, onerror) {
/**
* unload the specified asset to free memory
- * @memberof loader
* @param {Asset} asset
* @returns {boolean} true if unloaded
* @example me.loader.unload({name: "avatar", type:"image"});
@@ -729,7 +722,6 @@ export function unload(asset) {
/**
* unload all resources to free memory
- * @memberof loader
* @example me.loader.unloadAll();
* @category Assets
*/
@@ -842,7 +834,6 @@ export function unloadAll() {
/**
* return the specified TMX/TSX object
- * @memberof loader
* @param {string} elt - name of the tmx/tsx element ("map1");
* @returns {object} requested element or null if not found
* @category Assets
@@ -858,7 +849,6 @@ export function getTMX(elt) {
/**
* return the specified Binary object
- * @memberof loader
* @param {string} elt - name of the binary object ("ymTrack");
* @returns {object} requested element or null if not found
* @category Assets
@@ -874,7 +864,6 @@ export function getBinary(elt) {
/**
* return the specified Image Object
- * @memberof loader
* @param {string} image - name of the Image element ("tileset-platformer");
* @returns {HTMLImageElement|CompressedImage|null} requested element or null if not found
* @category Assets
@@ -891,7 +880,6 @@ export function getImage(image) {
/**
* return the specified JSON Object
- * @memberof loader
* @param {string} elt - name of the json file
* @returns {JSON}
* @category Assets
@@ -907,7 +895,6 @@ export function getJSON(elt) {
/**
* return the specified OBJ model data
- * @memberof loader
* @param {string} elt - name of the OBJ file (as specified in the preload list)
* @returns {object} parsed OBJ data with `vertices` (Float32Array), `uvs` (Float32Array), `indices` (Uint16Array), and `vertexCount` (number), or null if not found
* @category Assets
@@ -977,7 +964,6 @@ export function getOBJ(elt) {
* call via `me.level.load(name)` — exactly like a Tiled map. Reach for
* `getGLTF` only when you want to inspect the raw descriptor (e.g. to frame
* a `Camera3d` from the embedded camera).
- * @memberof loader
* @param {string} elt - name of the glTF/GLB file (as specified in the preload list)
* @returns {GLTFData|null} the parsed scene descriptor, or `null` if not found
* @category Assets
@@ -1035,7 +1021,6 @@ export function getGLTF(elt) {
* built-in rendering. Note that shader assets require an initialized
* Application (`await app.init()`) — an inherent precondition of the
* preload flow, since the loading screen itself needs the renderer.
- * @memberof loader
* @param {string} elt - name of the shader asset (as specified in the preload list)
* @returns {ShaderEffect|GLShader|null} the shared, precompiled shader, or `null` if not found
* @category Assets
@@ -1075,7 +1060,6 @@ export function getShader(elt) {
/**
* return the specified MTL material data
- * @memberof loader
* @param {string} elt - name of the MTL file (as specified in the preload list)
* @returns {object} map of material names to properties (`Kd`, `d`, `map_Kd`), or null if not found
* @category Assets
@@ -1113,7 +1097,6 @@ export function getMTL(elt) {
/**
* return the specified Video Object
- * @memberof loader
* @param {string} elt - name of the video file
* @returns {HTMLVideoElement}
* @category Assets
@@ -1129,7 +1112,6 @@ export function getVideo(elt) {
/**
* return the specified FontFace Object
- * @memberof loader
* @param {string} elt - name of the font file
* @returns {FontFace}
* @category Assets
diff --git a/packages/melonjs/src/loader/loadingscreen.js b/packages/melonjs/src/loader/loadingscreen.js
index 375cf9474a..3df80d536e 100644
--- a/packages/melonjs/src/loader/loadingscreen.js
+++ b/packages/melonjs/src/loader/loadingscreen.js
@@ -17,6 +17,7 @@ import logo_url from "./melonjs_logo.png";
class ProgressBar extends Renderable {
/**
* @ignore
+ * @internal
*/
constructor(x, y, w, h) {
super(x, y, w, h);
@@ -36,6 +37,7 @@ class ProgressBar extends Renderable {
/**
* make sure the screen is refreshed every frame
* @ignore
+ * @internal
*/
onProgressUpdate(progress) {
this.progress = ~~(progress * this.width);
@@ -45,6 +47,7 @@ class ProgressBar extends Renderable {
/**
* draw function
* @ignore
+ * @internal
*/
draw(renderer, viewport) {
// draw the progress bar
@@ -68,6 +71,7 @@ class ProgressBar extends Renderable {
/**
* Called by engine before deleting the object
* @ignore
+ * @internal
*/
onDestroyEvent() {
off(LOADER_PROGRESS, this.onProgressUpdate, this);
@@ -78,27 +82,32 @@ class ProgressBar extends Renderable {
/**
* a default loading screen
* @ignore
+ * @internal
*/
class DefaultLoadingScreen extends Stage {
/**
* @ignore
+ * @internal
*/
progressBar = null;
/**
* @ignore
+ * @internal
*/
logoSprite = null;
/**
* reference to the application instance
* @ignore
+ * @internal
*/
#app = null;
/**
* whether the cleanup has already run
* @ignore
+ * @internal
*/
#cleanedUp = false;
@@ -116,6 +125,7 @@ class DefaultLoadingScreen extends Stage {
/**
* call when the loader is resetted
* @ignore
+ * @internal
*/
onResetEvent(app) {
const barHeight = 8;
@@ -155,6 +165,7 @@ class DefaultLoadingScreen extends Stage {
/**
* Remove loading screen children and unload the logo
* @ignore
+ * @internal
*/
#cleanup() {
this.#cleanedUp = true;
@@ -186,6 +197,7 @@ class DefaultLoadingScreen extends Stage {
/**
* Called by engine before deleting the object
* @ignore
+ * @internal
*/
onDestroyEvent() {
// remove the listener in case state.change() is called
diff --git a/packages/melonjs/src/loader/parsers/aseprite.js b/packages/melonjs/src/loader/parsers/aseprite.js
index a2bee7c7cd..494672a92f 100644
--- a/packages/melonjs/src/loader/parsers/aseprite.js
+++ b/packages/melonjs/src/loader/parsers/aseprite.js
@@ -91,6 +91,7 @@ class Reader {
* Decompress a zlib-compressed Uint8Array via the DecompressionStream API
* (zlib format = "deflate" stream type per the WHATWG Compression Streams spec).
* @ignore
+ * @internal
*/
async function inflate(bytes) {
const stream = new Response(bytes).body.pipeThrough(
@@ -103,6 +104,7 @@ async function inflate(bytes) {
* Decode a cel's pixel buffer (per the file's color depth) into a flat
* RGBA Uint8ClampedArray sized for ImageData.
* @ignore
+ * @internal
*/
function decodeCelPixels(raw, w, h, depth, palette, transparentIndex) {
const out = new Uint8ClampedArray(w * h * 4);
@@ -152,6 +154,7 @@ function decodeCelPixels(raw, w, h, depth, palette, transparentIndex) {
* Cel image data is already decompressed at this stage but still per-cel —
* compositing happens in a second pass so linked cels can resolve.
* @ignore
+ * @internal
*/
async function parseAsepriteFile(buffer) {
const r = new Reader(buffer);
@@ -394,6 +397,7 @@ async function parseAsepriteFile(buffer) {
* each visible cel onto its frame at (cel.x, cel.y). Returns the composited
* canvas (HTMLCanvasElement or OffscreenCanvas).
* @ignore
+ * @internal
*/
function composite(parsed) {
const { width, height, depth, frames, layers, palette, transparentIndex } =
@@ -479,6 +483,7 @@ function composite(parsed) {
* in src/video/texture/parser/aseprite.js — meta.app must include
* "aseprite" so identifyFormat() picks the right route.
* @ignore
+ * @internal
*/
function buildAtlasJSON(parsed, imageName) {
const { width, height, frames, tags } = parsed;
@@ -511,6 +516,7 @@ function buildAtlasJSON(parsed, imageName) {
* Convert a canvas to an ImageBitmap when possible (matches the regular image
* parser's cache shape so the renderer's texture cache treats it identically).
* @ignore
+ * @internal
*/
async function canvasToBitmap(canvas) {
if (
@@ -549,6 +555,7 @@ export async function parseAseprite(buffer, imageName = "default") {
* @param {Object} [settings]
* @returns {number}
* @ignore
+ * @internal
*/
export function preloadAseprite(data, onload, onerror, settings) {
fetchData(data.src, "arrayBuffer", settings)
diff --git a/packages/melonjs/src/loader/parsers/audio.js b/packages/melonjs/src/loader/parsers/audio.js
index a8b7086f36..82f02afe25 100644
--- a/packages/melonjs/src/loader/parsers/audio.js
+++ b/packages/melonjs/src/loader/parsers/audio.js
@@ -17,6 +17,7 @@ import { load } from "../../audio/playback.ts";
* @param {Object} [settings] - Additional settings to be passed when loading the asset
* @returns {number} the amount of corresponding resource parsed/preloaded
* @ignore
+ * @internal
*/
export function preloadAudio(data, onload, onerror, settings) {
return load(data, onload, onerror, settings);
@@ -27,6 +28,7 @@ export function preloadAudio(data, onload, onerror, settings) {
* @param {string} name - asset name
* @returns {boolean} true if unloaded
* @ignore
+ * @internal
*/
export function unloadAudio(name) {
return unload(name);
@@ -35,6 +37,7 @@ export function unloadAudio(name) {
/**
* unload all audio assets
* @ignore
+ * @internal
*/
export function unloadAllAudio() {
unloadAll();
diff --git a/packages/melonjs/src/loader/parsers/binary.js b/packages/melonjs/src/loader/parsers/binary.js
index c679cb67d9..bb1b2a6c71 100644
--- a/packages/melonjs/src/loader/parsers/binary.js
+++ b/packages/melonjs/src/loader/parsers/binary.js
@@ -9,6 +9,7 @@ import { binList } from "../cache.js";
* @param {Object} [settings] - Additional settings to be passed when loading the asset
* @returns {number} the amount of corresponding resource parsed/preloaded
* @ignore
+ * @internal
*/
export function preloadBinary(data, onload, onerror, settings) {
fetchData(data.src, "arrayBuffer", settings)
diff --git a/packages/melonjs/src/loader/parsers/compressed_textures/compressed_image.js b/packages/melonjs/src/loader/parsers/compressed_textures/compressed_image.js
index 6f65416627..e363e9de69 100644
--- a/packages/melonjs/src/loader/parsers/compressed_textures/compressed_image.js
+++ b/packages/melonjs/src/loader/parsers/compressed_textures/compressed_image.js
@@ -27,6 +27,10 @@ let _renderer;
// gracefully capture a reference to the active renderer without adding more cyclic redundancy
once(VIDEO_INIT, (renderer) => {
+ /**
+ * @ignore
+ * @internal
+ */
_renderer = renderer;
});
@@ -46,6 +50,7 @@ const EXT_REQUIREMENTS = {
* @param {string} imgExt - file extension
* @returns {boolean}
* @ignore
+ * @internal
*/
function hasRequiredExtension(imgExt) {
const requirements = EXT_REQUIREMENTS[imgExt];
diff --git a/packages/melonjs/src/loader/parsers/compressed_textures/parseDDS.js b/packages/melonjs/src/loader/parsers/compressed_textures/parseDDS.js
index a33a433134..d397a9c1e8 100644
--- a/packages/melonjs/src/loader/parsers/compressed_textures/parseDDS.js
+++ b/packages/melonjs/src/loader/parsers/compressed_textures/parseDDS.js
@@ -41,6 +41,7 @@ function blockSize(format) {
* @param {ArrayBuffer} data - the DDS file data
* @returns {CompressedImage} a compressed texture object with mipmaps, width, height, format
* @ignore
+ * @internal
*/
export function parseDDS(data) {
// validate magic number
diff --git a/packages/melonjs/src/loader/parsers/compressed_textures/parseKTX.js b/packages/melonjs/src/loader/parsers/compressed_textures/parseKTX.js
index 8b624f68a3..2df4bd2785 100644
--- a/packages/melonjs/src/loader/parsers/compressed_textures/parseKTX.js
+++ b/packages/melonjs/src/loader/parsers/compressed_textures/parseKTX.js
@@ -15,6 +15,7 @@ const KTX_HEADER_SIZE = 64;
* @param {ArrayBuffer} data - the KTX file data
* @returns {CompressedImage} a compressed texture object with mipmaps, width, height, format
* @ignore
+ * @internal
*/
export function parseKTX(data) {
const idView = new Uint8Array(data, 0, 12);
diff --git a/packages/melonjs/src/loader/parsers/compressed_textures/parseKTX2.js b/packages/melonjs/src/loader/parsers/compressed_textures/parseKTX2.js
index 147481fd31..399e29b3d1 100644
--- a/packages/melonjs/src/loader/parsers/compressed_textures/parseKTX2.js
+++ b/packages/melonjs/src/loader/parsers/compressed_textures/parseKTX2.js
@@ -73,6 +73,7 @@ const VKFORMAT_TO_WEBGL = {
* @param {ArrayBuffer} data - the KTX2 file data
* @returns {CompressedImage} a compressed texture object with mipmaps, width, height, format
* @ignore
+ * @internal
*/
export function parseKTX2(data) {
const idView = new Uint8Array(data, 0, 12);
diff --git a/packages/melonjs/src/loader/parsers/compressed_textures/parsePKM.js b/packages/melonjs/src/loader/parsers/compressed_textures/parsePKM.js
index f724595c93..c1509ec1e7 100644
--- a/packages/melonjs/src/loader/parsers/compressed_textures/parsePKM.js
+++ b/packages/melonjs/src/loader/parsers/compressed_textures/parsePKM.js
@@ -45,6 +45,7 @@ const PKM_FORMAT_TO_WEBGL = {
* @param {ArrayBuffer} data - the raw PKM file data
* @returns {CompressedImage} a compressed texture object
* @ignore
+ * @internal
*/
export function parsePKM(data) {
const header = new DataView(data, 0, PKM_HEADER_SIZE);
diff --git a/packages/melonjs/src/loader/parsers/compressed_textures/parsePVR.js b/packages/melonjs/src/loader/parsers/compressed_textures/parsePVR.js
index e8f6fd655a..88a6efd7e3 100644
--- a/packages/melonjs/src/loader/parsers/compressed_textures/parsePVR.js
+++ b/packages/melonjs/src/loader/parsers/compressed_textures/parsePVR.js
@@ -70,6 +70,7 @@ function levelBufferSize(format, width, height) {
* @param {ArrayBuffer} data - the PVR file data
* @returns {CompressedImage} a compressed texture object with mipmaps, width, height, format
* @ignore
+ * @internal
*/
export function parsePVR(data) {
const header = new Uint32Array(data, 0, PVR_HEADER_LENGTH);
diff --git a/packages/melonjs/src/loader/parsers/fontface.js b/packages/melonjs/src/loader/parsers/fontface.js
index 7fc51513d7..80f490fb78 100644
--- a/packages/melonjs/src/loader/parsers/fontface.js
+++ b/packages/melonjs/src/loader/parsers/fontface.js
@@ -7,6 +7,7 @@ import { fontList } from "../cache.js";
* @param {Function} [onerror] - function to be called in case of error
* @returns {number} the amount of corresponding resource parsed/preloaded
* @ignore
+ * @internal
* @example
* preloadFontFace([
* { name: "'kenpixel'", type: "fontface", src: "data/font/kenvector_future.woff2" }
diff --git a/packages/melonjs/src/loader/parsers/gltf.js b/packages/melonjs/src/loader/parsers/gltf.js
index 3b5c060a32..3dd16a04ae 100644
--- a/packages/melonjs/src/loader/parsers/gltf.js
+++ b/packages/melonjs/src/loader/parsers/gltf.js
@@ -18,6 +18,7 @@ import { specularFromMetallicRoughness } from "./pbr.ts";
* Out of scope: skinning (vertex skinning / JOINTS_0 / WEIGHTS_0), morph
* targets, full PBR maps, KHR extensions, Draco compression.
* @ignore
+ * @internal
*/
// glTF componentType -> TypedArray + DataView reader
@@ -45,6 +46,7 @@ const TYPE_COUNT = {
* @param {ArrayBuffer} arrayBuffer
* @returns {{ json: object, bin: Uint8Array | null }}
* @ignore
+ * @internal
*/
export function parseGLB(arrayBuffer) {
const dv = new DataView(arrayBuffer);
@@ -86,6 +88,7 @@ export function parseGLB(arrayBuffer) {
* (e.g. a GLB parsed straight from an ArrayBuffer in a test) — the caller then
* fails with a clear "external resource" message instead of fetching garbage.
* @ignore
+ * @internal
*/
function resolveURI(uri, baseURI) {
if (baseURI === undefined || baseURI === null) {
@@ -104,6 +107,7 @@ function resolveURI(uri, baseURI) {
/**
* Decode a single base64 `data:` URI payload into a Uint8Array.
* @ignore
+ * @internal
*/
function decodeDataURI(uri) {
const base64 = uri.slice(uri.indexOf(",") + 1);
@@ -120,6 +124,7 @@ function decodeDataURI(uri) {
* (no uri), embedded `data:` URIs, and external `.bin` files fetched relative
* to the asset URL (`baseURI`). Async because external buffers are fetched.
* @ignore
+ * @internal
*/
function resolveBuffers(json, bin, baseURI, settings) {
return Promise.all(
@@ -148,6 +153,7 @@ function resolveBuffers(json, bin, baseURI, settings) {
* Read an accessor into a flat TypedArray (stride-aware, non-interleaved
* fast-path covered as a subset).
* @ignore
+ * @internal
*/
export function readAccessor(json, buffers, accessorIndex) {
const accessor = json.accessors[accessorIndex];
@@ -202,6 +208,7 @@ export function readAccessor(json, buffers, accessorIndex) {
* @param {object} attributes - the extension's `attributes` map
* @returns {object|undefined} `{count, translation, rotation, scale}`, or undefined when empty
* @ignore
+ * @internal
*/
/**
* Scale a normalized-integer quaternion accessor back to [-1, 1].
@@ -209,6 +216,7 @@ export function readAccessor(json, buffers, accessorIndex) {
* @param {number} componentType - the accessor's glTF componentType
* @returns {ArrayLike} the de-normalized quaternion components
* @ignore
+ * @internal
*/
function normalizeQuaternions(raw, componentType) {
// float components are already in range
@@ -240,6 +248,7 @@ function normalizeQuaternions(raw, componentType) {
* @param {object} attributes - the extension's `attributes` map
* @returns {object|undefined} `{count, translation, rotation, scale}`, or undefined when empty
* @ignore
+ * @internal
*/
function readInstanceAttributes(json, buffers, attributes) {
if (!attributes) {
@@ -322,6 +331,7 @@ function readInstanceAttributes(json, buffers, attributes) {
* and `VEC4`, and the three glTF color encodings: float `0..1`, and normalized
* `UNSIGNED_BYTE` / `UNSIGNED_SHORT`.
* @ignore
+ * @internal
*/
function readVertexColors(json, buffers, accessorIndex) {
const accessor = json.accessors[accessorIndex];
@@ -361,6 +371,7 @@ const IDENTITY = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
* @param {number[]} scale - [sx, sy, sz]
* @returns {number[]} `out`
* @ignore
+ * @internal
*/
export function composeTRSInto(out, translation, rotation, scale) {
const [tx, ty, tz] = translation;
@@ -404,12 +415,17 @@ export function composeTRSInto(out, translation, rotation, scale) {
* @param {number[]} scale - [sx, sy, sz]
* @returns {number[]} 16-element column-major matrix
* @ignore
+ * @internal
*/
export function composeTRS(translation, rotation, scale) {
return composeTRSInto(new Array(16), translation, rotation, scale);
}
-/** Compose a node's local matrix from its `matrix` or TRS fields. @ignore */
+/**
+ * Compose a node's local matrix from its `matrix` or TRS fields.
+ * @ignore
+ * @internal
+ */
export function nodeLocalMatrix(node) {
if (node.matrix) {
return node.matrix.slice();
@@ -431,6 +447,7 @@ export function nodeLocalMatrix(node) {
* @param {number} vertexCount
* @returns {Float32Array} x,y,z normals, one per vertex
* @ignore
+ * @internal
*/
function computeFlatNormals(positions, indices, vertexCount) {
const normals = new Float32Array(vertexCount * 3);
@@ -478,7 +495,11 @@ function computeFlatNormals(positions, indices, vertexCount) {
return normals;
}
-/** Normalize a 3-component vector (returns +Y on a zero-length input). @ignore */
+/**
+ * Normalize a 3-component vector (returns +Y on a zero-length input).
+ * @ignore
+ * @internal
+ */
function normalize3(v) {
const len = Math.hypot(v[0], v[1], v[2]);
return len > 1e-8 ? [v[0] / len, v[1] / len, v[2] / len] : [0, 1, 0];
@@ -489,6 +510,7 @@ function normalize3(v) {
* `a` or `b` (results are written as they're computed). In-place so the
* per-frame pose path allocates nothing.
* @ignore
+ * @internal
*/
export function multiplyMatrixInto(out, a, b) {
for (let col = 0; col < 4; col++) {
@@ -503,7 +525,11 @@ export function multiplyMatrixInto(out, a, b) {
return out;
}
-/** Allocating form of {@link multiplyMatrixInto}: `a * b` → fresh array. @ignore */
+/**
+ * Allocating form of {@link multiplyMatrixInto}: `a * b` → fresh array.
+ * @ignore
+ * @internal
+ */
export function multiplyMatrix(a, b) {
return multiplyMatrixInto(new Array(16), a, b);
}
@@ -525,6 +551,7 @@ export function multiplyMatrix(a, b) {
* knobs, and palette expansion belongs to the decoder.
* @returns {Promise}
* @ignore
+ * @internal
*/
function decodeImage(json, buffers, imageIndex, baseURI, settings) {
const image = json.images[imageIndex];
@@ -590,6 +617,7 @@ function decodeImage(json, buffers, imageIndex, baseURI, settings) {
* Decode a Blob to an ImageBitmap, falling back to the element path on a
* platform without `createImageBitmap`.
* @ignore
+ * @internal
*/
function decodeBlob(blob) {
const viaElement = () => {
@@ -607,7 +635,10 @@ function decodeBlob(blob) {
return globalThis.createImageBitmap(blob).catch(viaElement);
}
-/** @ignore */
+/**
+ * @ignore
+ * @internal
+ */
function loadImageFromUrl(url, revoke = false, crossOrigin) {
return new Promise((resolve, reject) => {
const img = new Image();
@@ -642,6 +673,7 @@ function loadImageFromUrl(url, revoke = false, crossOrigin) {
* external resources (crossOrigin / withCredentials / nocache).
* @returns {Promise