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} `{ nodes, cameras, lights, bounds, graph, animations }` * @ignore + * @internal */ export async function parseGLTF(arrayBuffer, baseURI, settings) { const { json, bin } = parseGLB(arrayBuffer); @@ -1071,6 +1103,7 @@ export async function parseGLTF(arrayBuffer, baseURI, settings) { * @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 preloadGLTF(data, onload, onerror, settings) { if (typeof gltfList[data.name] !== "undefined") { diff --git a/packages/melonjs/src/loader/parsers/image.js b/packages/melonjs/src/loader/parsers/image.js index 129088f66b..2be050f3de 100644 --- a/packages/melonjs/src/loader/parsers/image.js +++ b/packages/melonjs/src/loader/parsers/image.js @@ -10,6 +10,7 @@ import { parseCompressedImage } from "./compressed_textures/compressed_image.js" * @param {Object} settings - fetch settings * @returns {Promise} resolves on success, rejects on failure (so the next source can be tried) * @ignore + * @internal */ function tryLoadSource(imgPath, imgName, settings) { const imgExt = getExtension(imgPath); @@ -61,6 +62,7 @@ function tryLoadSource(imgPath, imgName, settings) { * @param {Object} [settings] - Additional settings to be passed when loading the asset * @returns {number} the amount of corresponding resource parsed/preloaded * @ignore + * @internal * @example * preloadImages([ * { name : 'image1', src : 'images/image1.png'}, diff --git a/packages/melonjs/src/loader/parsers/json.js b/packages/melonjs/src/loader/parsers/json.js index 90d1a077ca..81b62f3a41 100644 --- a/packages/melonjs/src/loader/parsers/json.js +++ b/packages/melonjs/src/loader/parsers/json.js @@ -9,6 +9,7 @@ import { jsonList } 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 preloadJSON(data, onload, onerror, settings) { if (typeof jsonList[data.name] !== "undefined") { diff --git a/packages/melonjs/src/loader/parsers/mtl.js b/packages/melonjs/src/loader/parsers/mtl.js index e62aa639c9..5a7023fe58 100644 --- a/packages/melonjs/src/loader/parsers/mtl.js +++ b/packages/melonjs/src/loader/parsers/mtl.js @@ -51,6 +51,7 @@ const UNSUPPORTED_MAPS = new Set([ * @param {string} basePath - base URL path for resolving texture references * @returns {object} map of material names to their properties * @ignore + * @internal */ export function parseMTL(text, basePath) { const materials = {}; @@ -205,6 +206,7 @@ export function parseMTL(text, basePath) { * @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 preloadMTL(data, onload, onerror, settings) { if (typeof mtlList[data.name] !== "undefined") { diff --git a/packages/melonjs/src/loader/parsers/obj.js b/packages/melonjs/src/loader/parsers/obj.js index d15222ed1a..4484cd6f0d 100644 --- a/packages/melonjs/src/loader/parsers/obj.js +++ b/packages/melonjs/src/loader/parsers/obj.js @@ -38,6 +38,7 @@ const UINT16_VERTEX_LIMIT = 65536; * @param {number} z2 * @returns {number} the angle in radians * @ignore + * @internal */ function angleBetween(x1, y1, z1, x2, y2, z2) { const l1 = Math.hypot(x1, y1, z1); @@ -60,6 +61,7 @@ function angleBetween(x1, y1, z1, x2, y2, z2) { * @param {number} nz * @param {number} weight * @ignore + * @internal */ function addWeighted(target, at, nx, ny, nz, weight) { target[at] += nx * weight; @@ -114,6 +116,7 @@ function addWeighted(target, at, nx, ny, nz, weight) { * produce a `groups` array of length 1, so consumers don't need a * special case. * @ignore + * @internal */ export function parseOBJ(text) { const positions = []; @@ -187,6 +190,7 @@ export function parseOBJ(text) { * @param {string} part - face vertex string * @returns {number} UV index (0-based) or NO_UV * @ignore + * @internal */ function parseNormalIndex(part, slashIdx) { if (slashIdx === -1) { @@ -205,6 +209,7 @@ export function parseOBJ(text) { * @param {number} slashIdx - index of the first slash * @returns {number} UV index (0-based) or NO_UV * @ignore + * @internal */ function parseUVIndex(part, slashIdx) { if (slashIdx !== -1 && part[slashIdx + 1] !== SLASH_CHAR) { @@ -514,6 +519,7 @@ export function parseOBJ(text) { * @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 preloadOBJ(data, onload, onerror, settings) { if (typeof objList[data.name] !== "undefined") { diff --git a/packages/melonjs/src/loader/parsers/pbr.ts b/packages/melonjs/src/loader/parsers/pbr.ts index 5fb3f1a347..6cbe428b20 100644 --- a/packages/melonjs/src/loader/parsers/pbr.ts +++ b/packages/melonjs/src/loader/parsers/pbr.ts @@ -14,6 +14,7 @@ * says exactly what the artist wanted, where metallic/roughness only implies * it. * @ignore + * @internal */ /** @@ -21,6 +22,7 @@ * exponent runs away as roughness approaches 0, and a highlight narrower * than a pixel only aliases. * @ignore + * @internal */ export const MAX_SHININESS = 256; @@ -28,6 +30,7 @@ export const MAX_SHININESS = 256; * The specular reflectance of a non-metal, the standard value used by every * metallic/roughness workflow. Metals reflect their own base colour instead. * @ignore + * @internal */ export const DIELECTRIC_F0 = 0.04; @@ -36,6 +39,7 @@ export const DIELECTRIC_F0 = 0.04; * a {@link Mesh}, or `undefined` / `0` when the material implies no * highlight at all. * @ignore + * @internal */ export interface SpecularTerms { /** specular colour `[r, g, b]`, or `undefined` for none */ @@ -53,6 +57,7 @@ export interface SpecularTerms { * @param value - the authored factor * @returns the factor, or 1 * @ignore + * @internal */ function factor(value: unknown): number { return typeof value === "number" && Number.isFinite(value) ? value : 1; @@ -76,6 +81,7 @@ function factor(value: unknown): number { * @param baseColor - the material's base colour, `[r, g, b, a?]` * @returns the specular terms, inert when the material implies no highlight * @ignore + * @internal */ export function specularFromMetallicRoughness( roughness: unknown, diff --git a/packages/melonjs/src/loader/parsers/script.js b/packages/melonjs/src/loader/parsers/script.js index 46fb5f7c66..c4b1e9d2b8 100644 --- a/packages/melonjs/src/loader/parsers/script.js +++ b/packages/melonjs/src/loader/parsers/script.js @@ -6,6 +6,7 @@ * @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 preloadJavascript(data, onload, onerror, settings) { const script = globalThis.document.createElement("script"); diff --git a/packages/melonjs/src/loader/parsers/shader.js b/packages/melonjs/src/loader/parsers/shader.js index b925f09890..c12a236925 100644 --- a/packages/melonjs/src/loader/parsers/shader.js +++ b/packages/melonjs/src/loader/parsers/shader.js @@ -24,6 +24,10 @@ let _renderer; // cyclic redundancy (same pattern as the compressed-textures parser). `on` // rather than `once` so a re-init (renderer switch, tests) stays current. on(VIDEO_INIT, (renderer) => { + /** + * @ignore + * @internal + */ _renderer = renderer; }); @@ -42,6 +46,7 @@ on(VIDEO_INIT, (renderer) => { * @returns {ShaderEffect|GLShader} the compiled asset, flagged `shared` * @throws if called before any `app.init()` resolved (no renderer to compile against) * @ignore + * @internal */ export function compileShaderAsset(source) { if (typeof _renderer === "undefined") { @@ -127,6 +132,7 @@ export function compileShaderAsset(source) { * @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 preloadShader(data, onload, onerror, settings) { if (typeof shaderList[data.name] !== "undefined") { diff --git a/packages/melonjs/src/loader/parsers/tmx.js b/packages/melonjs/src/loader/parsers/tmx.js index 8cf8e95a87..714693acd0 100644 --- a/packages/melonjs/src/loader/parsers/tmx.js +++ b/packages/melonjs/src/loader/parsers/tmx.js @@ -12,6 +12,7 @@ import { tmxList } 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 preloadTMX(tmxData, onload, onerror, settings) { if (typeof tmxList[tmxData.name] !== "undefined") { @@ -21,6 +22,7 @@ export function preloadTMX(tmxData, onload, onerror, settings) { /** * @ignore + * @internal */ function addToTMXList(data) { // set the TMX content diff --git a/packages/melonjs/src/loader/parsers/video.js b/packages/melonjs/src/loader/parsers/video.js index 900b760e88..37c90fad26 100644 --- a/packages/melonjs/src/loader/parsers/video.js +++ b/packages/melonjs/src/loader/parsers/video.js @@ -12,6 +12,7 @@ import { videoList } 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 preloadVideo(data, onload, onerror, settings) { if (typeof videoList[data.name] !== "undefined") { diff --git a/packages/melonjs/src/math/noise.ts b/packages/melonjs/src/math/noise.ts index beedf1acfb..db0655e1de 100644 --- a/packages/melonjs/src/math/noise.ts +++ b/packages/melonjs/src/math/noise.ts @@ -129,7 +129,10 @@ export class Noise { offsetZ: number; // doubled permutation table (512 entries), seeded from `seed` - /** @ignore */ + /** + * @ignore + * @internal + */ private _perm: Uint8Array; constructor(settings: NoiseSettings = {}) { @@ -270,7 +273,10 @@ export class Noise { } // per-octave fractal shaping: fbm (passthrough), ridged, or ping-pong - /** @ignore */ + /** + * @ignore + * @internal + */ private _applyFractalShape(n: number) { if (this.fractalType === "ridged") { const r = 1 - Math.abs(n); @@ -283,7 +289,10 @@ export class Noise { } // single-octave 2D sample dispatched on `type` - /** @ignore */ + /** + * @ignore + * @internal + */ private _single2d(x: number, y: number) { if (this.type === "value") { return this._value2d(x, y); @@ -301,7 +310,10 @@ export class Noise { } // single-octave 3D sample dispatched on `type` - /** @ignore */ + /** + * @ignore + * @internal + */ private _single3d(x: number, y: number, z: number) { if (this.type === "value") { return this._value3d(x, y, z); @@ -321,13 +333,19 @@ export class Noise { // ── value noise ────────────────────────────────────────────────────── // hashed lattice value in [-1,1] - /** @ignore */ + /** + * @ignore + * @internal + */ private _hash2d(ix: number, iy: number) { const perm = this._perm; return perm[(perm[ix & 255] + iy) & 255] / 127.5 - 1; } - /** @ignore */ + /** + * @ignore + * @internal + */ private _value2d(x: number, y: number) { const ix = Math.floor(x); const iy = Math.floor(y); @@ -341,13 +359,19 @@ export class Noise { } // hashed lattice value in [-1,1] - /** @ignore */ + /** + * @ignore + * @internal + */ private _hash3d(ix: number, iy: number, iz: number) { const perm = this._perm; return perm[(perm[(perm[ix & 255] + iy) & 255] + iz) & 255] / 127.5 - 1; } - /** @ignore */ + /** + * @ignore + * @internal + */ private _value3d(x: number, y: number, z: number) { const ix = Math.floor(x); const iy = Math.floor(y); @@ -373,7 +397,10 @@ export class Noise { // ── value-cubic noise (Catmull-Rom interpolated lattice) ───────────── // cubic-interpolated row of 4 lattice values at row `cy` - /** @ignore */ + /** + * @ignore + * @internal + */ private _cubicRow2d(xi: number, cy: number, fx: number) { return cubic( this._hash2d(xi - 1, cy), @@ -384,7 +411,10 @@ export class Noise { ); } - /** @ignore */ + /** + * @ignore + * @internal + */ private _valueCubic2d(x: number, y: number) { const xi = Math.floor(x); const yi = Math.floor(y); @@ -399,7 +429,10 @@ export class Noise { } // cubic-interpolated plane of 4×4 lattice values at depth `cz` - /** @ignore */ + /** + * @ignore + * @internal + */ private _cubicPlane3d( xi: number, yi: number, @@ -438,7 +471,10 @@ export class Noise { return cubic(r0, r1, r2, r3, fy); } - /** @ignore */ + /** + * @ignore + * @internal + */ private _valueCubic3d(x: number, y: number, z: number) { const xi = Math.floor(x); const yi = Math.floor(y); @@ -456,7 +492,10 @@ export class Noise { // ── cellular (Worley F1) noise ─────────────────────────────────────── - /** @ignore */ + /** + * @ignore + * @internal + */ private _cellular2d(x: number, y: number) { const perm = this._perm; const jitter = this.cellularJitter; @@ -483,7 +522,10 @@ export class Noise { return Math.min(1, Math.sqrt(minDist)) * 2 - 1; } - /** @ignore */ + /** + * @ignore + * @internal + */ private _cellular3d(x: number, y: number, z: number) { const perm = this._perm; const jitter = this.cellularJitter; @@ -519,13 +561,19 @@ export class Noise { // ── perlin (improved) noise ────────────────────────────────────────── - /** @ignore */ + /** + * @ignore + * @internal + */ private _grad2(hash: number, x: number, y: number) { const h = (hash & 7) * 3; return GRAD3[h] * x + GRAD3[h + 1] * y; } - /** @ignore */ + /** + * @ignore + * @internal + */ private _perlin2d(x: number, y: number) { const perm = this._perm; const xi = Math.floor(x) & 255; @@ -548,13 +596,19 @@ export class Noise { return lerp(x1, x2, v) * 1.4; } - /** @ignore */ + /** + * @ignore + * @internal + */ private _grad3(hash: number, x: number, y: number, z: number) { const h = (hash % 12) * 3; return GRAD3[h] * x + GRAD3[h + 1] * y + GRAD3[h + 2] * z; } - /** @ignore */ + /** + * @ignore + * @internal + */ private _perlin3d(x: number, y: number, z: number) { const perm = this._perm; const xi = Math.floor(x) & 255; @@ -601,7 +655,10 @@ export class Noise { // ── simplex noise (Gustavson) ──────────────────────────────────────── - /** @ignore */ + /** + * @ignore + * @internal + */ private _simplex2d(xin: number, yin: number) { const perm = this._perm; let n0 = 0; @@ -649,7 +706,10 @@ export class Noise { return 70 * (n0 + n1 + n2); } - /** @ignore */ + /** + * @ignore + * @internal + */ private _simplex3d(xin: number, yin: number, zin: number) { const perm = this._perm; let n0 = 0; diff --git a/packages/melonjs/src/math/observableVector2d.ts b/packages/melonjs/src/math/observableVector2d.ts index ae66a9ebf7..0688dcfb4c 100644 --- a/packages/melonjs/src/math/observableVector2d.ts +++ b/packages/melonjs/src/math/observableVector2d.ts @@ -21,8 +21,20 @@ const isObservableProperty = ( * @category Math */ export class ObservableVector2d { + /** + * @ignore + * @internal + */ private _callback: () => void; + /** + * @ignore + * @internal + */ private _vector2d: Vector2d; + /** + * @ignore + * @internal + */ private _revoke: () => void; private callBackEnabled: boolean = true; diff --git a/packages/melonjs/src/math/observableVector3d.ts b/packages/melonjs/src/math/observableVector3d.ts index 4db95e9d95..9880e7dfdd 100644 --- a/packages/melonjs/src/math/observableVector3d.ts +++ b/packages/melonjs/src/math/observableVector3d.ts @@ -23,8 +23,20 @@ const isObservableProperty = ( * @category Math */ export class ObservableVector3d { + /** + * @ignore + * @internal + */ private _callback: () => void; + /** + * @ignore + * @internal + */ private _vector3d: Vector3d; + /** + * @ignore + * @internal + */ private _revoke: () => void; private callBackEnabled: boolean = true; diff --git a/packages/melonjs/src/math/vector2d.ts b/packages/melonjs/src/math/vector2d.ts index eca33c471a..558812c0dc 100644 --- a/packages/melonjs/src/math/vector2d.ts +++ b/packages/melonjs/src/math/vector2d.ts @@ -23,6 +23,7 @@ export class Vector2d { * @param [x] - x value of the vector * @param [y] - y value of the vector * @ignore + * @internal */ onResetEvent(x = 0, y = 0) { /** diff --git a/packages/melonjs/src/math/vertex.ts b/packages/melonjs/src/math/vertex.ts index 07b5e6edb4..2f4d4e9dcb 100644 --- a/packages/melonjs/src/math/vertex.ts +++ b/packages/melonjs/src/math/vertex.ts @@ -318,6 +318,7 @@ export function computeVertexNormal( * 2D cross product of vectors (p1-p0) and (p2-p0). * Positive = CCW, negative = CW, zero = collinear. * @ignore + * @internal */ function cross2d(p0: XYPoint, p1: XYPoint, p2: XYPoint): number { return (p1.x - p0.x) * (p2.y - p0.y) - (p1.y - p0.y) * (p2.x - p0.x); @@ -326,6 +327,7 @@ function cross2d(p0: XYPoint, p1: XYPoint, p2: XYPoint): number { /** * Squared distance between two 2D points. * @ignore + * @internal */ function dist2(a: XYPoint, b: XYPoint): number { const dx = a.x - b.x; diff --git a/packages/melonjs/src/particles/emitter.ts b/packages/melonjs/src/particles/emitter.ts index a8d1aa3c89..2ed506483b 100644 --- a/packages/melonjs/src/particles/emitter.ts +++ b/packages/melonjs/src/particles/emitter.ts @@ -18,17 +18,28 @@ import defaultEmitterSettings, { * distinct ones because a single scratch reused twice would clobber the first * operand mid-computation. * @ignore + * @internal */ const _m1 = new Matrix3d(); -/** @ignore */ +/** + * @ignore + * @internal + */ const _m2 = new Matrix3d(); -/** @ignore */ +/** + * @ignore + * @internal + */ const _correction = new Matrix3d(); -/** @ignore */ +/** + * @ignore + * @internal + */ const _rebase = new Vector2d(); /** * @ignore + * @internal */ function createDefaultParticleTexture( w: number = 8, @@ -49,6 +60,7 @@ function createDefaultParticleTexture( * Guards against the partial-override footgun where a user sets only the * `max` half of a range-style setting and the default of `min` ends up larger. * @ignore + * @internal */ function clampMinToMax( settings: ParticleEmitterSettings, @@ -111,31 +123,53 @@ export default class ParticleEmitter extends Container { */ settings: ParticleEmitterSettings; - /** @ignore */ + /** + * @ignore + * @internal + */ _stream: boolean; - /** @ignore */ + /** + * @ignore + * @internal + */ _frequencyTimer: number; - /** @ignore */ + /** + * @ignore + * @internal + */ _durationTimer: number; - /** @ignore */ + /** + * @ignore + * @internal + */ _enabled: boolean; - /** @ignore */ + /** + * @ignore + * @internal + */ _updateCount: number; - /** @ignore */ + /** + * @ignore + * @internal + */ _dt: number; - /** @ignore */ + /** + * @ignore + * @internal + */ _defaultParticle: CanvasRenderTarget | undefined; /** * The blend mode last fanned out to the particles, so a change to * {@link ParticleEmitter#blendMode} can be detected per frame. * @ignore + * @internal */ #appliedBlendMode: string = "normal"; @@ -144,6 +178,7 @@ export default class ParticleEmitter extends Container { * the precondition for completion detection (a brand-new emitter with zero * children must not count as "complete") * @ignore + * @internal */ _hasSpawned: boolean; @@ -151,6 +186,7 @@ export default class ParticleEmitter extends Container { * cached `timer.maxfps / 1000` — particles read this directly instead of * recomputing it on every spawn. * @ignore + * @internal */ _deltaInv: number; @@ -165,6 +201,7 @@ export default class ParticleEmitter extends Container { * emitter that actually uses a non-local space — emitters are few, unlike * particles, which allocate nothing. * @ignore + * @internal */ _spawnMap: Matrix3d | undefined; @@ -326,6 +363,7 @@ export default class ParticleEmitter extends Container { * particles holding coordinates measured against a frame that is no * longer theirs, teleporting the lot. * @ignore + * @internal * @param previous - the frame the live particles are currently in */ #rebase(previous: Container): void { @@ -358,6 +396,7 @@ export default class ParticleEmitter extends Container { * parent, or a custom target that IS the emitter), which then take the * local fast path with no correction at all. * @ignore + * @internal */ #frameOf(space: "local" | "world" | Container): Container { if (space === "local") { @@ -381,6 +420,7 @@ export default class ParticleEmitter extends Container { * The world transform of a reference frame — i.e. of the space that * container's children are drawn in. * @ignore + * @internal */ #worldFrame(frame: Container, out: Matrix3d): Matrix3d { return frame.getWorldTransform(out); @@ -405,6 +445,7 @@ export default class ParticleEmitter extends Container { * When the target is the emitter's own parent — the `"world"` case — the * whole ancestor chain cancels and no walk happens at all. * @ignore + * @internal * @returns the correction, or `undefined` in local mode */ #correctionMatrix(): Matrix3d | undefined { @@ -454,6 +495,7 @@ export default class ParticleEmitter extends Container { * local mode there is no correction and this is the inherited path * untouched. * @ignore + * @internal */ override draw( renderer: CanvasRenderer | WebGLRenderer, @@ -467,7 +509,10 @@ export default class ParticleEmitter extends Container { } // Add count particles in the game world - /** @ignore */ + /** + * @ignore + * @internal + */ addParticles(count: number): void { // Propagate the emitter's depth onto each new particle via // `Container.addChild(child, z)` so Camera3d projects them at @@ -553,6 +598,7 @@ export default class ParticleEmitter extends Container { /** * @ignore + * @internal */ override update(dt: number): boolean { // Fan a changed blend mode out to the particles. @@ -670,6 +716,7 @@ export default class ParticleEmitter extends Container { /** * Destroy function * @ignore + * @internal */ override destroy(): void { super.destroy(); diff --git a/packages/melonjs/src/particles/particle.ts b/packages/melonjs/src/particles/particle.ts index 8e41726fe5..fe27068c82 100644 --- a/packages/melonjs/src/particles/particle.ts +++ b/packages/melonjs/src/particles/particle.ts @@ -15,6 +15,7 @@ import ParticleEmitter from "./emitter.ts"; * Scratch for mapping a spawn point into the emitter's reference frame. * Consumed immediately, so one shared instance is enough. * @ignore + * @internal */ const _spawn = new Vector2d(); @@ -33,9 +34,25 @@ export default class Particle extends Renderable { wind: number; followTrajectory: boolean; onlyInViewport: boolean; + /** + * @ignore + * @internal + */ _deltaInv: number; + /** + * @ignore + * @internal + */ _halfW: number; + /** + * @ignore + * @internal + */ _halfH: number; + /** + * @ignore + * @internal + */ _angle: number; alive: boolean; @@ -77,11 +94,13 @@ export default class Particle extends Renderable { * base constructor chain (`Polygon.setVertices`) before a subclass's field * initializers have run, and writing an undeclared private field throws. * @ignore + * @internal */ _boundsDirty = true; /** * @ignore + * @internal */ onResetEvent(emitter: ParticleEmitter, newInstance: boolean = false) { // reset() guarantees `settings.image` is populated before particles spawn. @@ -210,6 +229,7 @@ export default class Particle extends Renderable { * Update the Particle
* This is automatically called by the game manager {@link game} * @ignore + * @internal * @param dt - time since the last update in milliseconds */ override update(dt: number) { @@ -325,6 +345,7 @@ export default class Particle extends Renderable { * particle specifically: no flip, no mask, and the anchor is zeroed, so * nothing the base method emits interacts with this. * @ignore + * @internal */ override preDraw(renderer: CanvasRenderer | WebGLRenderer) { super.preDraw(renderer); @@ -339,6 +360,7 @@ export default class Particle extends Renderable { * missing. The base implementation would add this particle's own `pos` on * top of a matrix that already contains it, counting it twice. * @ignore + * @internal */ /** * Bounds are recomputed here rather than when `pos` moves, so a particle @@ -348,6 +370,7 @@ export default class Particle extends Renderable { * asks for a recompute, such as {@link Container} aggregating child bounds * under `enableChildBoundsUpdate`, still gets fresh values back. * @ignore + * @internal */ override getBounds() { const bounds = super.getBounds(); @@ -392,6 +415,7 @@ export default class Particle extends Renderable { * The container this particle's position is measured from — its emitter * under the default local reference space, something else otherwise. * @ignore + * @internal */ #frameOrigin(): Renderable { const emitter = this.ancestor as ParticleEmitter; @@ -412,6 +436,7 @@ export default class Particle extends Renderable { * necessarily its parent — so summing up the ancestor chain, as the base * implementation does, would measure from the wrong place. * @ignore + * @internal */ override getAbsolutePosition() { const origin = this.#frameOrigin(); @@ -434,6 +459,7 @@ export default class Particle extends Renderable { * With the placement in `currentTransform` and `autoTransform` off, the * base composition would describe a transform this class never applies. * @ignore + * @internal */ override getLocalTransform(out: Matrix3d) { return out.copy(this.currentTransform); @@ -441,6 +467,7 @@ export default class Particle extends Renderable { /** * @ignore + * @internal */ override draw(renderer: CanvasRenderer | WebGLRenderer) { const w = this.width; diff --git a/packages/melonjs/src/physics/bounds.ts b/packages/melonjs/src/physics/bounds.ts index 5bb35fa840..98811fbd9c 100644 --- a/packages/melonjs/src/physics/bounds.ts +++ b/packages/melonjs/src/physics/bounds.ts @@ -17,6 +17,10 @@ const _addFrameScratch = new Point(); * @category Geometry */ export class Bounds { + /** + * @ignore + * @internal + */ _center: Vector2d; type: string; min: XYPoint; diff --git a/packages/melonjs/src/physics/broadphase/broadphase.ts b/packages/melonjs/src/physics/broadphase/broadphase.ts index 5882d5224d..a0211a2fb4 100644 --- a/packages/melonjs/src/physics/broadphase/broadphase.ts +++ b/packages/melonjs/src/physics/broadphase/broadphase.ts @@ -38,6 +38,7 @@ export interface Broadphase { * Maintained by `insert` / `remove` so {@link Broadphase.isPrunable} * and {@link Broadphase.hasChildren} are O(1) reads. * @ignore + * @internal */ _subtreeCount: number; diff --git a/packages/melonjs/src/physics/broadphase/octree.ts b/packages/melonjs/src/physics/broadphase/octree.ts index 513ae202de..17dc2daa47 100644 --- a/packages/melonjs/src/physics/broadphase/octree.ts +++ b/packages/melonjs/src/physics/broadphase/octree.ts @@ -9,6 +9,7 @@ import type { Broadphase } from "./broadphase.ts"; * floating items without allocating. Mirrors QuadTree's `QT_VECTOR` * — only one query runs at a time, single-instance is safe. * @ignore + * @internal */ const OT_VECTOR = new Vector2d(); @@ -88,6 +89,7 @@ export interface FrustumPlane { * from this, clear/collapse returns to it. Keeps steady-state * allocations at zero across the per-frame world rebuild. * @ignore + * @internal */ const OT_ARRAY: Octree[] = []; @@ -121,6 +123,7 @@ function OT_ARRAY_PUSH(ot: Octree) { * `pos.z` if the item doesn't expose `getAbsolutePosition` (test * doubles do this), and finally `0` for items with no pos at all. * @ignore + * @internal */ function itemZ(item: OctreeItem): number { if (typeof item.getAbsolutePosition === "function") { @@ -147,12 +150,14 @@ export default class Octree implements Broadphase { /** * see {@link QuadTree._subtreeCount} — same invariant. * @ignore + * @internal */ _subtreeCount: number; /** * see {@link QuadTree._retrieveScratch} — same contract. * @ignore + * @internal */ _retrieveScratch: OctreeItem[] | null; @@ -303,6 +308,7 @@ export default class Octree implements Broadphase { * @param item - the object to classify * @returns near-half octant index (0-3) or -1 * @ignore + * @internal */ _quadrantXY(item: OctreeItem): number { const bounds = item.getBounds(); @@ -631,6 +637,7 @@ export default class Octree implements Broadphase { * Loose-floats implementation. Recursive subnode walks call this * directly to bypass the Sphere/floats dispatch on every node. * @ignore + * @internal */ _querySphereInternal( cx: number, @@ -889,6 +896,7 @@ export default class Octree implements Broadphase { * provably outside ANY one plane, i.e. wholly outside the * frustum. * @ignore + * @internal */ _outsideFrustum(planes: FrustumPlane[]): boolean { const b = this.bounds; @@ -920,6 +928,7 @@ export default class Octree implements Broadphase { * node's octant. dir components may be zero; the axis with zero * direction degenerates to a point-in-slab test. * @ignore + * @internal */ _overlapsRay( fromX: number, @@ -986,7 +995,10 @@ export default class Octree implements Broadphase { return true; } - /** @ignore */ + /** + * @ignore + * @internal + */ _overlapsAABB(aabb: AABB3d): boolean { const b = this.bounds; const right = b.left + b.width; @@ -1002,7 +1014,10 @@ export default class Octree implements Broadphase { ); } - /** @ignore */ + /** + * @ignore + * @internal + */ _overlapsSphere(cx: number, cy: number, cz: number, r: number): boolean { const b = this.bounds; const minX = b.left; @@ -1024,15 +1039,22 @@ export default class Octree implements Broadphase { * QuadTree. `getChildren` is optional because leaf renderables don't * have it; the recursive walk narrows via {@link hasGetChildren}. * @ignore + * @internal */ interface ContainerOrChild extends OctreeItem { addChild?: (...args: unknown[]) => unknown; getChildren?: () => ContainerOrChild[]; } -/** @ignore */ +/** + * @ignore + * @internal + */ type ContainerLike = { getChildren(): ContainerOrChild[] }; -/** @ignore */ +/** + * @ignore + * @internal + */ type ContainerLikeOptional = { getChildren?(): ContainerOrChild[] }; /** diff --git a/packages/melonjs/src/physics/broadphase/quadtree.ts b/packages/melonjs/src/physics/broadphase/quadtree.ts index 80582c4b4d..53b93111a5 100644 --- a/packages/melonjs/src/physics/broadphase/quadtree.ts +++ b/packages/melonjs/src/physics/broadphase/quadtree.ts @@ -54,6 +54,7 @@ export type QuadTreeSortFn = (a: QuadTreeItem, b: QuadTreeItem) => number; /** * a pool of `QuadTree` objects * @ignore + * @internal */ const QT_ARRAY: QuadTree[] = []; @@ -61,6 +62,7 @@ const QT_ARRAY: QuadTree[] = []; * will pop a quadtree object from the array * or create a new one if the array is empty * @ignore + * @internal */ function QT_ARRAY_POP( world: World, @@ -85,6 +87,7 @@ function QT_ARRAY_POP( /** * Push back a quadtree back into the array * @ignore + * @internal */ function QT_ARRAY_PUSH(qt: QuadTree) { QT_ARRAY.push(qt); @@ -93,6 +96,7 @@ function QT_ARRAY_PUSH(qt: QuadTree) { /** * a temporary vector object to be reused * @ignore + * @internal */ const QT_VECTOR = new Vector2d(); @@ -116,6 +120,7 @@ export default class QuadTree implements Broadphase { * and `remove` so `isPrunable` / `hasChildren` are O(1) reads * instead of O(tree-size) walks. Reset to 0 in `clear`. * @ignore + * @internal */ _subtreeCount: number; @@ -125,6 +130,7 @@ export default class QuadTree implements Broadphase { * narrow-phase query. Only the root allocates one; recursive * subnode calls receive the array via the `result` arg. * @ignore + * @internal */ _retrieveScratch: QuadTreeItem[] | null; @@ -615,6 +621,7 @@ export default class QuadTree implements Broadphase { * `getChildren` is optional because leaf renderables don't have it; * the recursive `insertContainer` narrows via {@link hasGetChildren}. * @ignore + * @internal */ interface ContainerOrChild extends QuadTreeItem { addChild?: (...args: unknown[]) => unknown; @@ -629,9 +636,13 @@ interface ContainerOrChild extends QuadTreeItem { * shape; the optional variant covers the case where the World's lazy * `children` accessor returns `undefined`. * @ignore + * @internal */ type ContainerLike = { getChildren(): ContainerOrChild[] }; -/** @ignore */ +/** + * @ignore + * @internal + */ type ContainerLikeOptional = { getChildren?(): ContainerOrChild[] }; /** diff --git a/packages/melonjs/src/physics/builtin/body.js b/packages/melonjs/src/physics/builtin/body.js index 549ecb6380..e12b07f0f6 100644 --- a/packages/melonjs/src/physics/builtin/body.js +++ b/packages/melonjs/src/physics/builtin/body.js @@ -67,6 +67,7 @@ export default class Body { * mis-doc and broke downstream `shapes.length` reads in * TypeScript. * @ignore + * @internal * @type {(Polygon|Line|Ellipse|Point)[]} */ this.shapes = []; @@ -76,6 +77,7 @@ export default class Body { * The body collision mask, that defines what should collide with what.
* (by default will collide with all entities) * @ignore + * @internal * @type {number} * @default collision.types.ALL_OBJECT * @see collision.types @@ -562,6 +564,7 @@ export default class Body { * pivot — see `MatterAdapter.syncFromPhysics`). Internal helper used * by both the per-step integrator and {@link Body#setAngle}. * @ignore + * @internal */ _syncAngleTransform() { const t = this.ancestor?.currentTransform; @@ -671,6 +674,8 @@ export default class Body { * @param {object} [source] - the object passed to `addShape`; omitted when * the shape was built here from a pool and has no user-supplied original * @private + * @ignore + * @internal */ _initShapeCollision(stored, source) { // Stable identity for shape-level contact tracking (#1596). @@ -856,6 +861,7 @@ export default class Body { * large body more. Clamped to a minimum of 1 to keep divisions * well-defined even on degenerate 0-size bodies. * @ignore + * @internal */ _recomputePseudoInertia() { const w = this.bounds.width; @@ -1137,8 +1143,7 @@ export default class Body { /** * Returns true if the any of the shape composing the body contains the given point. - * @param {number|Vector2d} x - x coordinate or a vector point to check - * @param {number} [y] - y coordinate + * @param {...(number|Vector2d)} args - either `x, y` coordinates, or a single {@link Vector2d} * @returns {boolean} true if contains * @example * if (mySprite.body.contains(10, 10)) { @@ -1336,6 +1341,7 @@ export default class Body { /** * Destroy function
* @ignore + * @internal */ destroy() { // push back instance into object pool. diff --git a/packages/melonjs/src/physics/builtin/detector.js b/packages/melonjs/src/physics/builtin/detector.js index 105771aa47..8005dbea9f 100644 --- a/packages/melonjs/src/physics/builtin/detector.js +++ b/packages/melonjs/src/physics/builtin/detector.js @@ -55,6 +55,7 @@ const SAT_LOOKUP = { * Shape-type pairs already reported as unsupported, so a mismatched pair * warns once instead of once per frame per pair. * @ignore + * @internal */ const reportedMissingPairs = new Set(); @@ -94,12 +95,14 @@ class Detector { * the previous step. Diffed against `_frameSeen` at end of step * to fire `onCollisionEnd` for pairs that just separated. * @ignore + * @internal */ this._activePairs = new Map(); /** * Pairs seen during the current step. Built up as the per-object * `collisions()` calls run; consumed by `endFrame()`. * @ignore + * @internal */ this._frameSeen = new Map(); /** @@ -116,6 +119,7 @@ class Detector { * world mutation). Slot 0 is used for the original-a-side * dispatch, slot 1 for the original-b-side. * @ignore + * @internal */ this._symViews = [ { @@ -163,9 +167,13 @@ class Detector { * `endFrame()` to fire `onShapeCollisionEnd`. Populated only when someone * subscribes, so a game that does not use the feature keeps these empty. * @ignore + * @internal */ this._activeShapePairs = new Map(); - /** @ignore */ + /** + * @ignore + * @internal + */ this._frameShapeSeen = new Map(); /** @@ -174,6 +182,7 @@ class Detector { * `indexShapeA` are always the RECEIVER's shape. Two slots because both * sides may be live at once when a handler mutates the world. * @ignore + * @internal */ this._shapeViews = [ { @@ -217,10 +226,18 @@ class Detector { * single pre-bound function rather than a closure allocated per body pair * per frame. * @ignore + * @internal */ this._contactObjA = null; + /** + * @ignore + * @internal + */ this._contactObjB = null; - /** @ignore */ + /** + * @ignore + * @internal + */ this._onShapeContact = (shapeA, indexA, shapeB, indexB, isTrigger, res) => { this._dispatchShapeContact( shapeA, @@ -241,6 +258,7 @@ class Detector { * `overlapN` / `overlapV` negated, `normal = +overlapN` (the MTV * of original b). * @ignore + * @internal */ _fillSymView(slot, satResponse, flip) { const view = this._symViews[slot]; @@ -291,6 +309,7 @@ class Detector { * "seen this frame" set so the end-of-step diff can fire * `onCollisionEnd` for pairs that no longer overlap. * @ignore + * @internal */ beginFrame() { this._frameSeen.clear(); @@ -303,6 +322,7 @@ class Detector { * - pairs in active but not seen → fire onCollisionEnd * - swap active ← seen for the next step's diff * @ignore + * @internal */ endFrame() { for (const [key, pair] of this._activePairs) { @@ -369,6 +389,7 @@ class Detector { * have separated, so every geometric field is zeroed rather than left * holding the last overlap, which would read as a live contact. * @ignore + * @internal */ _fillEndedView(slot, receiver, partner, ownShape, otherShape) { const view = this._shapeViews[slot]; @@ -399,6 +420,7 @@ class Detector { * using their GUID. Returns undefined if either lacks a GUID (defensive * — detached or pool-recycled objects mid-step). * @ignore + * @internal */ _pairKey(a, b) { const ga = a.GUID; @@ -421,6 +443,7 @@ class Detector { * body has no contact left to resolve, so this reports failure and the * caller falls through instead of throwing. * @ignore + * @internal * @returns {boolean} true when the pair was re-measured */ _retest(bodyA, bodyB, shapeA, shapeB, response) { @@ -459,6 +482,7 @@ class Detector { * derived from array position, because `removeShape()` re-indexes every * surviving shape. * @ignore + * @internal */ _shapePairKey(a, b, shapeA, shapeB) { const ga = a.GUID; @@ -491,6 +515,7 @@ class Detector { * never declares these handlers performs exactly the narrowphase work it * did before the feature existed. * @ignore + * @internal */ _wantsShapeContacts(obj) { return ( @@ -505,6 +530,7 @@ class Detector { * `_fillSymView`: `flip=false` builds the view for `response.a`'s side, * `flip=true` for `response.b`'s, so `shapeA` is always the receiver's. * @ignore + * @internal */ _fillShapeView(slot, satResponse, flip, shapeA, shapeB, isTrigger) { const view = this._shapeViews[slot]; @@ -555,6 +581,7 @@ class Detector { * Fire Start / Active for one overlapping shape pair. Called back from * `collides()` once per pair, in scan order. * @ignore + * @internal */ _dispatchShapeContact(shapeA, shapeB, isTrigger, response) { const objA = this._contactObjA; @@ -607,6 +634,7 @@ class Detector { * would hold two renderables (and everything they reach) against garbage * collection until the next subscribed pair happened to overwrite them. * @ignore + * @internal */ _clearContactPair() { this._contactObjA = null; @@ -799,6 +827,7 @@ class Detector { /** * find all the collisions for the specified object using a broadphase algorithm * @ignore + * @internal * @param {Renderable|Container|Entity|Sprite|NineSliceSprite} objA - object to be tested for collision * @returns {boolean} in case of collision, false otherwise */ @@ -1074,6 +1103,7 @@ class Detector { /** * Checks for object colliding with the given line * @ignore + * @internal * @param {Line} line - line to be tested for collision * @param {Array.} [result] - a user defined array that will be populated with intersecting physic objects. * @returns {Array.} an array of intersecting physic objects diff --git a/packages/melonjs/src/physics/builtin/sat.js b/packages/melonjs/src/physics/builtin/sat.js index 6e8809b893..1c6e039b65 100644 --- a/packages/melonjs/src/physics/builtin/sat.js +++ b/packages/melonjs/src/physics/builtin/sat.js @@ -18,18 +18,21 @@ import { Vector2d } from "../../math/vector2d.ts"; /** * Constants for Vornoi regions * @ignore + * @internal */ const LEFT_VORNOI_REGION = -1; /** * Constants for Vornoi regions * @ignore + * @internal */ const MIDDLE_VORNOI_REGION = 0; /** * Constants for Vornoi regions * @ignore + * @internal */ const RIGHT_VORNOI_REGION = 1; @@ -37,6 +40,7 @@ const RIGHT_VORNOI_REGION = 1; * A pool of `Vector` objects that are used in calculations to avoid allocating memory. * @type {Array.} * @ignore + * @internal */ const T_VECTORS = []; for (let v = 0; v < 10; v++) { @@ -45,6 +49,7 @@ for (let v = 0; v < 10; v++) { /** * Stack index for the T_VECTORS pool. Points to the next available slot. * @ignore + * @internal */ let T_VECTORS_IDX = 10; @@ -52,6 +57,7 @@ let T_VECTORS_IDX = 10; * A pool of arrays of numbers used in calculations to avoid allocating memory. * @type {Array.>} * @ignore + * @internal */ const T_ARRAYS = []; for (let a = 0; a < 5; a++) { @@ -60,6 +66,7 @@ for (let a = 0; a < 5; a++) { /** * Stack index for the T_ARRAYS pool. Points to the next available slot. * @ignore + * @internal */ let T_ARRAYS_IDX = 5; @@ -68,6 +75,7 @@ let T_ARRAYS_IDX = 5; * resulting in a one dimensional range of the minimum and * maximum value on that axis. * @ignore + * @internal * @param {Array.} points - The points to flatten. * @param {Vector2d} normal - The unit vector axis to flatten on. * @param {Array.} result - An array. After calling this function, @@ -96,6 +104,7 @@ function flattenPointsOn(points, normal, result) { * Check whether two convex polygons are separated by the specified * axis (must be a unit vector). * @ignore + * @internal * @param {Vector2d} aPos - The position of the first polygon. * @param {Vector2d} bPos - The position of the second polygon. * @param {Array.} aPoints - The points in the first polygon. @@ -184,6 +193,7 @@ function isSeparatingAxis(aPos, bPos, aPoints, bPoints, axis, response) { * * * @ignore + * @internal * @param {Vector2d} line - The line segment. * @param {Vector2d} point - The point. * @returns {number} LEFT_VORNOI_REGION (-1) if it is the left region, @@ -210,6 +220,7 @@ function vornoiRegion(line, point) { /** * Checks whether polygons collide. * @ignore + * @internal * @param {Renderable|Container|Entity|Sprite|NineSliceSprite} a - a reference to the object A. * @param {Polygon} polyA - a reference to the object A Polygon to be tested * @param {Renderable|Container|Entity|Sprite|NineSliceSprite} b - a reference to the object B. @@ -266,6 +277,7 @@ export function testPolygonPolygon(a, polyA, b, polyB, response) { /** * Check if two Ellipse collide. * @ignore + * @internal * @param {Renderable|Container|Entity|Sprite|NineSliceSprite} a - a reference to the object A. * @param {Ellipse} ellipseA - a reference to the object A Ellipse to be tested * @param {Renderable|Container|Entity|Sprite|NineSliceSprite} b - a reference to the object B. @@ -342,6 +354,7 @@ export function testEllipseEllipse(a, ellipseA, b, ellipseB, response) { /** * Check if a polygon and an ellipse collide. * @ignore + * @internal * @param {Renderable|Container|Entity|Sprite|NineSliceSprite} a - a reference to the object A. * @param {Polygon} polyA - a reference to the object A Polygon to be tested * @param {Renderable|Container|Entity|Sprite|NineSliceSprite} b - a reference to the object B. @@ -520,6 +533,7 @@ export function testPolygonEllipse(a, polyA, b, ellipseB, response) { * **NOTE:** This is slightly less efficient than testPolygonEllipse as it just * runs testPolygonEllipse and reverses the response at the end. * @ignore + * @internal * @param {Renderable|Container|Entity|Sprite|NineSliceSprite} a - a reference to the object A. * @param {Ellipse} ellipseA - a reference to the object A Ellipse to be tested * @param {Renderable|Container|Entity|Sprite|NineSliceSprite} b - a reference to the object B. diff --git a/packages/melonjs/src/physics/builtin/sat3d.js b/packages/melonjs/src/physics/builtin/sat3d.js index f47f7d69e3..95b607193a 100644 --- a/packages/melonjs/src/physics/builtin/sat3d.js +++ b/packages/melonjs/src/physics/builtin/sat3d.js @@ -19,6 +19,7 @@ import { * except that all three terms are read in 3D. `getAbsolutePosition()` already * sums z across the whole ancestor chain. * @ignore + * @internal */ function absCenter(renderable, box, out) { const anc = renderable.ancestor.getAbsolutePosition(); @@ -48,6 +49,7 @@ const _centerB = [0, 0, 0]; * `onCollision` handler safely inert on a depth-only contact rather than * wrong. * @ignore + * @internal * @param {Renderable} a - a reference to the object A. * @param {Box3d} boxA - a reference to the object A Box3d to be tested * @param {Renderable} b - a reference to the object B. @@ -145,6 +147,7 @@ export function testBox3dBox3d(a, boxA, b, boxB, response) { * `overlapZ` is left at `0` by construction, since neither participant has a * finite depth to resolve against. * @ignore + * @internal */ export function testBox3dPolygon(a, boxA, b, polyB, response) { return testPolygonPolygon(a, boxA._footprint, b, polyB, response); @@ -153,6 +156,7 @@ export function testBox3dPolygon(a, boxA, b, polyB, response) { /** * Planar-shape-first form of {@link testBox3dPolygon}. * @ignore + * @internal */ export function testPolygonBox3d(a, polyA, b, boxB, response) { return testPolygonPolygon(a, polyA, b, boxB._footprint, response); @@ -162,6 +166,7 @@ export function testPolygonBox3d(a, polyA, b, boxB, response) { * {@link Box3d} against an {@link Ellipse}, with the ellipse unbounded along * Z. See {@link testBox3dPolygon}. * @ignore + * @internal */ export function testBox3dEllipse(a, boxA, b, ellipseB, response) { return testPolygonEllipse(a, boxA._footprint, b, ellipseB, response); @@ -171,6 +176,7 @@ export function testBox3dEllipse(a, boxA, b, ellipseB, response) { * {@link Ellipse} against a {@link Box3d}, with the ellipse unbounded along * Z. See {@link testBox3dPolygon}. * @ignore + * @internal */ export function testEllipseBox3d(a, ellipseA, b, boxB, response) { return testEllipsePolygon(a, ellipseA, b, boxB._footprint, response); diff --git a/packages/melonjs/src/physics/collision.js b/packages/melonjs/src/physics/collision.js index 9d61ec7861..a06ddc1557 100644 --- a/packages/melonjs/src/physics/collision.js +++ b/packages/melonjs/src/physics/collision.js @@ -14,8 +14,6 @@ import { game } from "../application/application.ts"; export const collision = { /** * The maximum number of children that a quadtree node can contain before it is split into sub-nodes. - * @name maxChildren - * @memberof collision * @public * @type {number} * @default 8 @@ -25,8 +23,6 @@ export const collision = { /** * The maximum number of levels that the quadtree will create. - * @name maxDepth - * @memberof collision * @public * @type {number} * @default 4 @@ -48,8 +44,6 @@ export const collision = { * @property {number} ALL_OBJECT all of the above (including user-defined types) * @readonly * @enum {number} - * @name types - * @memberof collision * @see Body.setCollisionMask * @see Body.collisionType * @example @@ -97,8 +91,6 @@ export const collision = { /** * Checks for object colliding with the given line - * @name rayCast - * @memberof collision * @public * @param {Line} line - line to be tested for collision * @param {Array.} [result] - a user defined array that will be populated with intersecting physic objects. diff --git a/packages/melonjs/src/physics/response.js b/packages/melonjs/src/physics/response.js index 01a9b313f1..3f997396c1 100644 --- a/packages/melonjs/src/physics/response.js +++ b/packages/melonjs/src/physics/response.js @@ -55,7 +55,6 @@ class ResponseObject { * Call this between tests if you are going to reuse a single
* Response object for multiple intersection tests
* (recommended as it will avoid allocating extra memory)
- * @name clear * @public * @returns {object} this object for chaining */ diff --git a/packages/melonjs/src/physics/world.js b/packages/melonjs/src/physics/world.js index 9327a54d33..b4214bfbf6 100644 --- a/packages/melonjs/src/physics/world.js +++ b/packages/melonjs/src/physics/world.js @@ -25,6 +25,7 @@ import BuiltinAdapter from "./builtin/builtin-adapter.ts"; * their own body storage). Frozen so `world.bodies.add(x)` throws * `TypeError` instead of silently mutating a throwaway. * @ignore + * @internal */ const EMPTY_BODIES = Object.freeze(new Set()); @@ -182,6 +183,7 @@ export default class World extends Container { * broadphase nobody reads on `LEVEL_LOADED`, and it cannot be garbage * collected because both handlers close over it. * @ignore + * @internal */ destroy() { off(GAME_RESET, this.reset, this); diff --git a/packages/melonjs/src/polyfill/ellipse.ts b/packages/melonjs/src/polyfill/ellipse.ts index 3baaa48d3b..43b11aaa65 100644 --- a/packages/melonjs/src/polyfill/ellipse.ts +++ b/packages/melonjs/src/polyfill/ellipse.ts @@ -3,7 +3,10 @@ * Uses cubic bezier curves to approximate the ellipse when native support is unavailable. */ -/** @ignore */ +/** + * @ignore + * @internal + */ function ellipse( this: CanvasRenderingContext2D | Path2D, x: number, diff --git a/packages/melonjs/src/polyfill/roundrect.ts b/packages/melonjs/src/polyfill/roundrect.ts index b62107e3a4..66b7bf4486 100644 --- a/packages/melonjs/src/polyfill/roundrect.ts +++ b/packages/melonjs/src/polyfill/roundrect.ts @@ -3,7 +3,10 @@ * @version 0.0.1 */ -/** @ignore */ +/** + * @ignore + * @internal + */ function roundRect( this: CanvasRenderingContext2D, x: number, @@ -239,7 +242,10 @@ function roundRect( this.closePath(); this.moveTo(x, y); - /** @ignore */ + /** + * @ignore + * @internal + */ function toDOMPointInit(value: { x: number; y: number; @@ -250,7 +256,10 @@ function roundRect( return { x, y, z, w }; } - /** @ignore */ + /** + * @ignore + * @internal + */ function parseRadiiArgument( value: any, ): @@ -295,12 +304,18 @@ function roundRect( return [toUnrestrictedNumber(value)]; } - /** @ignore */ + /** + * @ignore + * @internal + */ function toUnrestrictedNumber(value: any) { return +value; } - /** @ignore */ + /** + * @ignore + * @internal + */ function toCornerPoint(value: any) { const asNumber = toUnrestrictedNumber(value); if (Number.isFinite(asNumber)) { @@ -322,7 +337,10 @@ function roundRect( }; } - /** @ignore */ + /** + * @ignore + * @internal + */ function fixOverlappingCorners(corners: any) { const [upperLeft, upperRight, lowerRight, lowerLeft] = corners; const factors = [ diff --git a/packages/melonjs/src/renderable/anchorPoint.ts b/packages/melonjs/src/renderable/anchorPoint.ts index 4d17c4caae..3c6a0ba744 100644 --- a/packages/melonjs/src/renderable/anchorPoint.ts +++ b/packages/melonjs/src/renderable/anchorPoint.ts @@ -9,6 +9,7 @@ * Named anchor-point presets accepted anywhere `settings.anchorPoint` is — * self-documenting shorthands for the common `{x, y}` pairs. * @ignore + * @internal */ export const ANCHOR_POINT_PRESETS = Object.freeze({ center: Object.freeze({ x: 0.5, y: 0.5 }), @@ -26,6 +27,7 @@ export const ANCHOR_POINT_PRESETS = Object.freeze({ * An anchor value as accepted by `settings.anchorPoint`: a preset name or * any object with numeric `x`/`y` (plain object, Vector2d, ObservablePoint). * @ignore + * @internal */ export type AnchorPointValue = | keyof typeof ANCHOR_POINT_PRESETS @@ -57,6 +59,7 @@ const isAnchorPair = (value: unknown): value is { x: number; y: number } => { * constructed before can start throwing; * - without (new surfaces, e.g. Sprite3d): throws. * @ignore + * @internal */ export function resolveAnchorPoint( value: unknown, diff --git a/packages/melonjs/src/renderable/animation.ts b/packages/melonjs/src/renderable/animation.ts index fdc2b72960..00060ad8e8 100644 --- a/packages/melonjs/src/renderable/animation.ts +++ b/packages/melonjs/src/renderable/animation.ts @@ -18,6 +18,7 @@ export interface AnimationOptions { * `false` return holds the last frame. Carried so callers can preserve that * exact contract; not part of the public options shape. * @ignore + * @internal */ legacyFn?: boolean; } diff --git a/packages/melonjs/src/renderable/colorlayer.js b/packages/melonjs/src/renderable/colorlayer.js index 52001869e3..b4be36e01f 100644 --- a/packages/melonjs/src/renderable/colorlayer.js +++ b/packages/melonjs/src/renderable/colorlayer.js @@ -56,6 +56,7 @@ export default class ColorLayer extends Renderable { /** * Destroy function * @ignore + * @internal */ destroy() { colorPool.release(this.color); diff --git a/packages/melonjs/src/renderable/container.js b/packages/melonjs/src/renderable/container.js index 11001845fc..4e53fceebe 100644 --- a/packages/melonjs/src/renderable/container.js +++ b/packages/melonjs/src/renderable/container.js @@ -10,6 +10,7 @@ import Renderable from "./renderable.js"; /** * Private function to re-use for object removal in a defer * @ignore + * @internal */ function deferredRemove(child, keepalive) { this.removeChildNow(child, keepalive); @@ -22,6 +23,7 @@ function deferredRemove(child, keepalive) { * per comparison. Safe to be module-scoped: JS is single-threaded and * sort is synchronous within each container. * @ignore + * @internal */ let _depthCamX = 0; let _depthCamY = 0; @@ -51,6 +53,7 @@ let _depthOffsetZ = 0; * camera sees slightly-imperfect order which is the standard * compromise for split-screen rendering. * @ignore + * @internal */ function captureDepthCamera() { const stage = state.current(); @@ -91,6 +94,7 @@ function captureDepthCamera() { * parked at a large negative depth is as far away as one parked at the * same positive depth. * @ignore + * @internal */ function depthKey(r) { if (r.floating === true) { @@ -109,11 +113,24 @@ function depthKey(r) { * each child's LOCAL `pos.x/y/z` into world space without paying for * an `ancestor.getAbsolutePosition()` walk per comparator call. * @ignore + * @internal */ function captureDepthOffset(container) { const abs = container.getAbsolutePosition(); + /** + * @ignore + * @internal + */ _depthOffsetX = abs.x; + /** + * @ignore + * @internal + */ _depthOffsetY = abs.y; + /** + * @ignore + * @internal + */ _depthOffsetZ = abs.z; } @@ -130,6 +147,7 @@ function captureDepthOffset(container) { * with no `bodyDef`, routed through `world.addBody(child.body)`. * BuiltinAdapter-only. * @ignore + * @internal */ function registerChildBody(child, worldContainer) { if (child.bodyDef) { @@ -193,6 +211,7 @@ export default class Container extends Renderable { /** * keep track of pending sort * @ignore + * @internal */ this.pendingSort = null; @@ -206,6 +225,7 @@ export default class Container extends Renderable { /** * The array of children of this container. * @ignore + * @internal */ this.children = undefined; @@ -214,8 +234,14 @@ export default class Container extends Renderable { * value : "x", "y", "z" * @type {string} * @default "z" + * @ignore + * @internal */ this._sortOn = "z"; + /** + * @ignore + * @internal + */ this._comparator = this._sortZ; /** @@ -798,6 +824,7 @@ export default class Container extends Renderable { /** * @ignore + * @internal * @param {...*} _args - reserved; widens the signature so subclass * overrides like `onActivateEvent(app)` remain structurally * assignable to the base Container/Renderable type. @@ -1055,6 +1082,7 @@ export default class Container extends Renderable { /** * @ignore + * @internal * @param {...*} _args - reserved; widens the signature so subclass * overrides like `onDeactivateEvent(app)` remain structurally * assignable to the base Container/Renderable type. @@ -1070,6 +1098,7 @@ export default class Container extends Renderable { /** * Z Sorting function * @ignore + * @internal */ _sortZ(a, b) { return b.pos.z - a.pos.z; @@ -1078,6 +1107,7 @@ export default class Container extends Renderable { /** * Reverse Z Sorting function * @ignore + * @internal */ _sortReverseZ(a, b) { return a.pos.z - b.pos.z; @@ -1098,6 +1128,7 @@ export default class Container extends Renderable { * `ObservableVector3d` pos — `pos.z` is always defined, no guard * needed here. * @ignore + * @internal */ _sortDepth(a, b) { // Translate each child's LOCAL `pos` into world space via the @@ -1115,6 +1146,7 @@ export default class Container extends Renderable { /** * X Sorting function * @ignore + * @internal */ _sortX(a, b) { return b.pos.z - a.pos.z || b.pos.x - a.pos.x; @@ -1123,6 +1155,7 @@ export default class Container extends Renderable { /** * Y Sorting function * @ignore + * @internal */ _sortY(a, b) { return b.pos.z - a.pos.z || b.pos.y - a.pos.y; @@ -1131,6 +1164,7 @@ export default class Container extends Renderable { /** * Destroy function
* @ignore + * @internal */ destroy() { // drop the root container's resize subscription before anything else — diff --git a/packages/melonjs/src/renderable/draggable.js b/packages/melonjs/src/renderable/draggable.js index ab9b223df7..66091d69ef 100644 --- a/packages/melonjs/src/renderable/draggable.js +++ b/packages/melonjs/src/renderable/draggable.js @@ -110,6 +110,7 @@ export class Draggable extends Renderable { /** * Destructor * @ignore + * @internal */ destroy() { off(POINTERMOVE, this.handlePointerMove); diff --git a/packages/melonjs/src/renderable/dragndrop.js b/packages/melonjs/src/renderable/dragndrop.js index 62a55af0ea..0d3a3ccf3d 100644 --- a/packages/melonjs/src/renderable/dragndrop.js +++ b/packages/melonjs/src/renderable/dragndrop.js @@ -24,25 +24,19 @@ export class DropTarget extends Renderable { /** * constant for the overlaps method - * @constant * @type {string} - * @name CHECKMETHOD_OVERLAP */ this.CHECKMETHOD_OVERLAP = "overlaps"; /** * constant for the contains method - * @constant * @type {string} - * @name CHECKMETHOD_CONTAINS */ this.CHECKMETHOD_CONTAINS = "contains"; /** * the checkmethod we want to use - * @constant * @type {string} - * @name checkMethod * @default "CHECKMETHOD_OVERLAP" */ this.checkMethod = this.CHECKMETHOD_OVERLAP; @@ -81,11 +75,13 @@ export class DropTarget extends Renderable { * Gets called when a draggable entity is dropped on the current entity * @param {Draggable} draggable - the draggable object that is dropped */ - drop() {} + // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars + drop(draggable) {} /** * Destructor * @ignore + * @internal */ destroy() { this.removeDragEndListener(); diff --git a/packages/melonjs/src/renderable/entity/entity.js b/packages/melonjs/src/renderable/entity/entity.js index abb4c4e647..7a89c62734 100644 --- a/packages/melonjs/src/renderable/entity/entity.js +++ b/packages/melonjs/src/renderable/entity/entity.js @@ -159,6 +159,10 @@ import Sprite from "../sprite.js"; * @category Game Objects */ export default class Entity extends Renderable { + /** + * @ignore + * @internal + */ static _deprecationWarned = false; /** @@ -192,6 +196,7 @@ export default class Entity extends Renderable { /** * The array of renderable children of this entity. * @ignore + * @internal */ this.children = []; @@ -292,7 +297,10 @@ export default class Entity extends Renderable { } } - /** @ignore */ + /** + * @ignore + * @internal + */ update(dt) { if (this.renderable) { this.isDirty |= this.renderable.update(dt); @@ -405,6 +413,7 @@ export default class Entity extends Renderable { /** * Destroy function * @ignore + * @internal */ destroy() { // free some property objects diff --git a/packages/melonjs/src/renderable/frameAnimation.js b/packages/melonjs/src/renderable/frameAnimation.js index b167e9f778..5a0e9e419c 100644 --- a/packages/melonjs/src/renderable/frameAnimation.js +++ b/packages/melonjs/src/renderable/frameAnimation.js @@ -49,6 +49,7 @@ export default class FrameAnimation { * the host renderable this engine draws through. * @type {object} * @ignore + * @internal */ this.host = host; @@ -56,13 +57,18 @@ export default class FrameAnimation { * geometry hook invoked on every frame change (see constructor). * @type {(region: object) => void} * @ignore + * @internal */ this._applyFrame = applyFrame; /** defined animations, keyed by id @type {object} */ this.anim = {}; - /** animation to chain to / completion callback on cycle end @ignore */ + /** + * animation to chain to / completion callback on cycle end + * @ignore + * @internal + */ this.resetAnim = undefined; /** current frame info @type {object} */ @@ -93,10 +99,18 @@ export default class FrameAnimation { /** pause flag — freezes the current frame @type {boolean} */ this.animationpause = false; - /** per-play speed multiplier (1 = authored speed) @ignore */ + /** + * per-play speed multiplier (1 = authored speed) + * @ignore + * @internal + */ this._animSpeed = 1; - /** set once a `loop:false` animation has finished its single cycle @ignore */ + /** + * set once a `loop:false` animation has finished its single cycle + * @ignore + * @internal + */ this._animDone = false; } @@ -349,6 +363,7 @@ export default class FrameAnimation { * this true, which is the point: only a genuinely torn-down host stops the * loop. * @ignore + * @internal * @returns {boolean} true while the current animation can still be read */ _isCurrentAnimationLive() { diff --git a/packages/melonjs/src/renderable/groundshadow.js b/packages/melonjs/src/renderable/groundshadow.js index 8d2a137672..9153af5f98 100644 --- a/packages/melonjs/src/renderable/groundshadow.js +++ b/packages/melonjs/src/renderable/groundshadow.js @@ -17,6 +17,7 @@ import Renderer from "./../video/renderer.js"; * in the scene shares one geometry and one texture, so a scene full of them * costs one draw each and no extra memory. * @ignore + * @internal */ /** @@ -24,6 +25,7 @@ import Renderer from "./../video/renderer.js"; * smooth when a shadow fills a good part of the screen, small enough that the * whole thing is a rounding error against any real texture. * @ignore + * @internal */ const FALLOFF_SIZE = 128; @@ -36,6 +38,7 @@ const FALLOFF_SIZE = 128; * source on the CPU means the shadow survives a lost context for free. It is * also why this can be module-level while the quad below cannot. * @ignore + * @internal */ let falloffCanvas = null; @@ -48,6 +51,7 @@ let falloffCanvas = null; * of light, and nothing has to be re-baked to change it. * @returns {HTMLCanvasElement|OffscreenCanvas} the shared falloff canvas * @ignore + * @internal */ export function getShadowFalloff() { if (falloffCanvas !== null) { @@ -90,6 +94,7 @@ export function getShadowFalloff() { * Drop the shared bake. Only the tests need this — the canvas is CPU-side and * costs 64 KB, so an application never has a reason to release it. * @ignore + * @internal */ export function resetShadowFalloff() { falloffCanvas = null; @@ -111,6 +116,7 @@ export function resetShadowFalloff() { * @param {number} vertexCount - how many vertices to read * @returns {boolean} true when the geometry is not flat in Y * @ignore + * @internal */ export function hasVerticalExtent(vertices, vertexCount) { if (vertices === undefined || vertexCount === 0) { @@ -148,6 +154,7 @@ export function hasVerticalExtent(vertices, vertexCount) { * Render space is Y-DOWN, so the ground plane is XZ and "up" is `-Y` — the * same convention `Sprite3d.WORLD_UP` states. * @ignore + * @internal */ const QUAD_VERTICES = new Float32Array([ -0.5, 0, -0.5, 0.5, 0, -0.5, 0.5, 0, 0.5, -0.5, 0, 0.5, @@ -179,6 +186,7 @@ const QUAD_NORMALS = new Float32Array([0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0]); * circular import: `Mesh` owns the shadow, not the other way round) * @returns {object} the shared shadow quad for that tier * @ignore + * @internal */ export function getShadowQuad(renderer, lit, MeshClass) { let quads = renderer._shadowQuads; @@ -234,6 +242,7 @@ export function getShadowQuad(renderer, lit, MeshClass) { * @param {number} version - the prototype's geometry version * @returns {object} the quad to draw this scatter's blobs from * @ignore + * @internal */ export function getInstancedShadowQuad(mesh, MeshClass, halfX, halfZ, version) { const key = `${mesh.lit === true}:${version}:${halfX}:${halfZ}`; @@ -277,6 +286,7 @@ export function getInstancedShadowQuad(mesh, MeshClass, halfX, halfZ, version) { * teardown so the retained GPU geometry goes with it. * @param {object} renderer - the renderer being torn down * @ignore + * @internal */ export function releaseShadowQuads(renderer) { const quads = renderer._shadowQuads; diff --git a/packages/melonjs/src/renderable/imagelayer.js b/packages/melonjs/src/renderable/imagelayer.js index 8b545793f5..82489eb31b 100644 --- a/packages/melonjs/src/renderable/imagelayer.js +++ b/packages/melonjs/src/renderable/imagelayer.js @@ -113,6 +113,10 @@ export default class ImageLayer extends Sprite { } set repeat(value) { + /** + * @ignore + * @internal + */ this._repeat = value; switch (this._repeat) { case "no-repeat": @@ -174,8 +178,13 @@ export default class ImageLayer extends Sprite { /** * createPattern function * @ignore + * @internal */ createPattern() { + /** + * @ignore + * @internal + */ this._pattern = this.parentApp.renderer.createPattern( this.image, this._repeat, @@ -185,6 +194,7 @@ export default class ImageLayer extends Sprite { /** * updateLayer function * @ignore + * @internal */ updateLayer() { const rx = this.ratio.x; @@ -250,6 +260,7 @@ export default class ImageLayer extends Sprite { * `Renderable.postDraw` cleans up symmetrically (`clearTint` / * `clearMask` / `endPostEffect` / `restore`). * @ignore + * @internal */ preDraw(renderer) { // save the context @@ -363,6 +374,7 @@ export default class ImageLayer extends Sprite { /** * Destroy function * @ignore + * @internal */ destroy() { vector2dPool.release(this.ratio); diff --git a/packages/melonjs/src/renderable/instanced_mesh.js b/packages/melonjs/src/renderable/instanced_mesh.js index f4c9419c0f..6a95bc094a 100644 --- a/packages/melonjs/src/renderable/instanced_mesh.js +++ b/packages/melonjs/src/renderable/instanced_mesh.js @@ -119,6 +119,7 @@ export default class InstancedMesh extends Mesh { * the instance vertex buffer. * @type {object} * @ignore + * @internal */ this.instanceLayout = instanceRecordLayout( settings.instanceColors === true, @@ -140,6 +141,7 @@ export default class InstancedMesh extends Mesh { * GPU copy knows its capacity assumption is stale * @type {number} * @ignore + * @internal */ this._instanceVersion = 0; @@ -151,24 +153,45 @@ export default class InstancedMesh extends Mesh { // first consumer to drain the span would leave the second stuck on // stale records forever. Each buffer records the revision it reached, // so a consumer that missed an edit re-uploads in full. - /** @ignore */ + /** + * @ignore + * @internal + */ this._instanceRevision = 0; // the revision the CURRENT span started from — a consumer at exactly // this revision can take the cheap partial upload - /** @ignore */ + /** + * @ignore + * @internal + */ this._spanFromRevision = 0; - /** @ignore */ + /** + * @ignore + * @internal + */ this._dirtyFirst = Infinity; - /** @ignore */ + /** + * @ignore + * @internal + */ this._dirtyLast = 0; - /** @ignore */ + /** + * @ignore + * @internal + */ this._instanceCount = 0; - /** @ignore */ + /** + * @ignore + * @internal + */ this._visibleInstanceCount = -1; // revision the cull box was last sized for - /** @ignore */ + /** + * @ignore + * @internal + */ this._cullRevision = -1; if (settings.instanceCount > 0) { @@ -440,6 +463,7 @@ export default class InstancedMesh extends Mesh { * nothing changed since the last upload. * @returns {number[]} the span * @ignore + * @internal */ dirtyRange() { // reuses one array: this is read once per instanced mesh per frame, @@ -459,6 +483,7 @@ export default class InstancedMesh extends Mesh { * @param {number} uploadedRevision - the revision that buffer holds * @returns {object} `{first, count, full, revision}` — float span, or `full` * @ignore + * @internal */ instanceUpload(uploadedRevision) { const revision = this._instanceRevision; @@ -476,6 +501,7 @@ export default class InstancedMesh extends Mesh { /** * Called by the batcher once the dirty span has been uploaded. * @ignore + * @internal */ clearInstanceDirty() { this._dirtyFirst = Infinity; @@ -503,6 +529,7 @@ export default class InstancedMesh extends Mesh { * pixels across at the group origin: pan the camera just past that origin * and every instance disappears at once, while still on screen. * @ignore + * @internal */ _refreshCullVolume() { if (this._instanceCount === 0) { @@ -524,6 +551,10 @@ export default class InstancedMesh extends Mesh { } } } + /** + * @ignore + * @internal + */ this._cullRadius = Math.max(radius, 1); } // Widen the box rather than resizing the renderable: `width`/`height` @@ -550,7 +581,10 @@ export default class InstancedMesh extends Mesh { getBounds3d() { if (this._bounds3d === undefined) { - /** @ignore */ + /** + * @ignore + * @internal + */ this._bounds3d = new AABB3d(); } const count = this._instanceCount; @@ -619,6 +653,7 @@ export default class InstancedMesh extends Mesh { * @param {CanvasRenderer} renderer - a renderer instance * @param {Camera2d} [viewport] - the camera rendering this frame * @ignore + * @internal */ _drawInstancesIndividually(renderer, viewport) { const count = this.visibleInstanceCount; @@ -651,6 +686,7 @@ export default class InstancedMesh extends Mesh { /** * Release the instance records along with the mesh. * @ignore + * @internal */ /** * Draw a ground shadow for every visible instance — one call for the whole @@ -666,6 +702,7 @@ export default class InstancedMesh extends Mesh { * built-in shading already reads as emissive. * @param {WebGLRenderer} renderer - the active renderer * @ignore + * @internal */ _drawInstancedGroundShadow(renderer) { if (typeof renderer.drawInstancedShadow !== "function") { @@ -750,6 +787,7 @@ const _composed = new Matrix3d(); * @param {Matrix3d} instance - the instance transform (written into) * @returns {Matrix3d} `instance`, now holding the product * @ignore + * @internal */ function multiplyInto(group, instance) { _composed.copy(group); diff --git a/packages/melonjs/src/renderable/mesh.js b/packages/melonjs/src/renderable/mesh.js index eb9c7f7b15..e9de9d2b25 100644 --- a/packages/melonjs/src/renderable/mesh.js +++ b/packages/melonjs/src/renderable/mesh.js @@ -69,6 +69,7 @@ const _combinedMatrix = new Matrix3d(); * @param {number} vertexCount - how many vertices the mesh has * @returns {Uint32Array} one packed RGBA8 colour per vertex * @ignore + * @internal */ function packVertexColors(source, vertexCount) { if (source.length !== vertexCount) { @@ -120,6 +121,7 @@ function resolveTextureAtlas(src, framewidth, frameheight) { * @param {number[]|Float32Array|undefined|null} src * @returns {Float32Array|undefined} * @ignore + * @internal */ function toEmissive(src) { if (src === undefined || src === null) { @@ -145,6 +147,7 @@ function toEmissive(src) { * @param {object} materials - MTL material table keyed by material name * @returns {{materialName: string|null, start: number, count: number, tint: Color, opacity: number}} draw descriptor for this group * @ignore + * @internal */ function resolveGroupMaterial(group, materials) { const mat = group.materialName ? materials[group.materialName] : null; @@ -197,6 +200,7 @@ function resolveGroupMaterial(group, materials) { * @param {number} [frameheight] - spritesheet cell height, as passed to the Mesh * @returns {Array<{texture: TextureAtlas, start: number, count: number}>|undefined} the per-texture draw ranges, or `undefined` when one binding covers the whole mesh * @ignore + * @internal */ function buildTextureGroups( groups, @@ -459,6 +463,10 @@ export default class Mesh extends Renderable { // losing the ability to restore the original (see // `_setupWorldSpace` for the rationale). Same reference — we // never mutate it in place. + /** + * @ignore + * @internal + */ this._indicesOriginal = this.indices; // working array for projected vertices (see the note below on when it @@ -755,15 +763,28 @@ export default class Mesh extends Renderable { * `getBounds3d()` per frame per shadow, which re-bounds every source * vertex through the model matrix. * @ignore + * @internal */ this._shadowHalfX = -1; + /** + * @ignore + * @internal + */ this._shadowHalfZ = -1; // the geometry version the two above (and `_shadowHasHeight`) were // measured at; -1 means "never". Recomputed when the mesh signals a // geometry change, so a deforming mesh — or a `Sprite3d` whose frame // bake rewrites `originalVertices` every animation step — does not keep // a blob frozen at whatever its first shadowed draw happened to see. + /** + * @ignore + * @internal + */ this._shadowGeomVersion = -1; + /** + * @ignore + * @internal + */ this._shadowHasHeight = false; /** @@ -1128,7 +1149,10 @@ export default class Mesh extends Renderable { // single anchoring mechanism (the Camera2d fallback loses its exact // pixel-shift anchor for such subclasses; that path is documented as // degraded for them anyway). Plain meshes keep the legacy 2D anchor. - /** @ignore */ + /** + * @ignore + * @internal + */ this._anchorBaked = false; // skip applying the 3D transform to the 2D renderer context in preDraw @@ -1136,17 +1160,26 @@ export default class Mesh extends Renderable { this.autoTransform = false; // pre-allocate points array and polygon for toPolygon() (avoids per-call allocation) - /** @ignore */ + /** + * @ignore + * @internal + */ this._hullPoints = Array.from({ length: this.vertexCount }, () => { return new Vector2d(); }); - /** @ignore */ + /** + * @ignore + * @internal + */ this._hullPolygon = null; // Bumped whenever the geometry itself changes, so a renderer holding // GPU-resident copies knows when to refresh them. Placement changes // (transform, position, tint) deliberately do NOT bump it. - /** @ignore */ + /** + * @ignore + * @internal + */ this._geometryVersion = 0; } @@ -1157,6 +1190,7 @@ export default class Mesh extends Renderable { * @param {number} [offsetY=0] - y offset added to each projected vertex * @param {number} [zScale=0] - scale factor for Z output (0 = skip Z, 1000 = depth buffer range) * @ignore + * @internal */ _projectVertices(offsetX = 0, offsetY = 0, zScale = 0) { _combinedMatrix.copy(this.projectionMatrix); @@ -1276,10 +1310,14 @@ export default class Mesh extends Renderable { * rotation rather than a reflection and so preserves triangle winding. * @returns {Matrix3d} the mesh's model matrix (reused instance) * @ignore + * @internal */ _composeModelMatrix() { if (this._modelMatrix === undefined) { - /** @ignore */ + /** + * @ignore + * @internal + */ this._modelMatrix = new Matrix3d(); } const out = this._modelMatrix.val; @@ -1319,6 +1357,7 @@ export default class Mesh extends Renderable { * @param {number} offsetY - world Y to place the mesh center at * @param {number} offsetZ - world Z to place the mesh center at * @ignore + * @internal */ _projectVerticesWorld(offsetX, offsetY, offsetZ) { const out = this.vertices; @@ -1368,6 +1407,7 @@ export default class Mesh extends Renderable { * scale (the common case); a strongly non-uniform scale would skew them * slightly — acceptable for the diffuse lighting path. * @ignore + * @internal */ _projectNormalsWorld() { const src = this.originalNormals; @@ -1420,6 +1460,7 @@ export default class Mesh extends Renderable { * `cullBackFaces: true`. * @param {boolean} [needsReversedIndices=true] - build the winding-reversed index copy. `false` on the retained path, which corrects winding with `frontFace` and would otherwise duplicate the index array for nothing. * @ignore + * @internal */ _setupWorldSpace(needsReversedIndices = true) { // Only the reflection bridge (left-handed, Y-only negate) inverts @@ -1444,8 +1485,16 @@ export default class Mesh extends Renderable { dst[i + 1] = src[i + 2]; dst[i + 2] = src[i + 1]; } + /** + * @ignore + * @internal + */ this._indicesReversed = dst; } + /** + * @ignore + * @internal + */ this._worldSpace = true; } @@ -1463,9 +1512,14 @@ export default class Mesh extends Renderable { * to use as the source of truth, captured here ONCE rather than per * frame. * @ignore + * @internal */ onActivateEvent(...args) { super.onActivateEvent(...args); + /** + * @ignore + * @internal + */ this._useWorldSpace = game.viewport instanceof Camera3d; } @@ -1480,6 +1534,7 @@ export default class Mesh extends Renderable { * rebuilds on its next draw rather than inheriting the previous * occupant's geometry. * @ignore + * @internal */ onDeactivateEvent(...args) { const renderer = this.parentApp?.renderer ?? game.renderer; @@ -1503,7 +1558,10 @@ export default class Mesh extends Renderable { */ getBounds3d() { if (this._bounds3d === undefined) { - /** @ignore */ + /** + * @ignore + * @internal + */ this._bounds3d = new AABB3d(); } // Bound the model-space geometry through this mesh's placement, rather @@ -1551,6 +1609,7 @@ export default class Mesh extends Renderable { * @param {WebGLRenderer|WebGPURenderer} renderer - the active renderer * @returns {boolean} true if a shadow should be drawn * @ignore + * @internal */ _castsGroundShadow(renderer) { if (typeof this.castGroundShadow === "boolean") { @@ -1572,6 +1631,7 @@ export default class Mesh extends Renderable { * Measure the model-space footprint the blob is built from, and whether the * geometry has any height at all — once per geometry version. * @ignore + * @internal */ _measureShadowFootprint() { const version = this._geometryVersion ?? 0; @@ -1609,6 +1669,7 @@ export default class Mesh extends Renderable { * uploaded once, so this is one draw and no allocation. * @param {WebGLRenderer} renderer - the active renderer * @ignore + * @internal */ _drawGroundShadow(renderer) { const quad = getShadowQuad(renderer, this.lit === true, Mesh); @@ -2030,6 +2091,7 @@ export default class Mesh extends Renderable { * Release this mesh's GPU-resident geometry, if a renderer is holding any, * then destroy the renderable. * @ignore + * @internal */ destroy() { // the fallback is load-bearing: a mesh that was never parented has no diff --git a/packages/melonjs/src/renderable/nineslicesprite.js b/packages/melonjs/src/renderable/nineslicesprite.js index f4f7ef80df..3b9f45de59 100644 --- a/packages/melonjs/src/renderable/nineslicesprite.js +++ b/packages/melonjs/src/renderable/nineslicesprite.js @@ -105,6 +105,7 @@ export default class NineSliceSprite extends Sprite { * let the per-frame source size shrink the panel to a single frame.) * @param {object} region - the texture region object * @ignore + * @internal */ _applyFrame(region) { // capture the expanded size BEFORE super runs: its `this.width =` writes @@ -122,6 +123,7 @@ export default class NineSliceSprite extends Sprite { /** * @ignore + * @internal */ draw(renderer) { // the frame to draw diff --git a/packages/melonjs/src/renderable/renderable.js b/packages/melonjs/src/renderable/renderable.js index 7e7ce5c25d..6fba2dab72 100644 --- a/packages/melonjs/src/renderable/renderable.js +++ b/packages/melonjs/src/renderable/renderable.js @@ -34,9 +34,13 @@ import pool from "../system/legacy_pool.js"; * never re-enters: `getLocalTransform` composes into `_level`, which is * consumed immediately. * @ignore + * @internal */ const _chain = []; -/** @ignore */ +/** + * @ignore + * @internal + */ const _level = new Matrix3d(); /** @@ -327,6 +331,7 @@ export default class Renderable extends Rect { /** * whether this renderable manages its own FBO lifecycle (e.g. Camera2d) * @ignore + * @internal */ this._postEffectManaged = false; @@ -351,6 +356,7 @@ export default class Renderable extends Rect { /** * to identify the object as a renderable object * @ignore + * @internal */ this.isRenderable = true; @@ -371,12 +377,14 @@ export default class Renderable extends Rect { /** * cache the absolute position of the renderable * @ignore + * @internal */ this._absPos = undefined; /** * keep track of when we flip * @ignore + * @internal */ this._flip = { x: false, @@ -386,18 +394,21 @@ export default class Renderable extends Rect { /** * viewport flag * @ignore + * @internal */ this._inViewport = false; /** * cache value for the parentApp * @ignore + * @internal */ this._parentApp = undefined; /** * renderable cache tint value used by the getter/setter * @ignore + * @internal */ this._tint = colorPool.get(255, 255, 255, 1.0); @@ -1197,7 +1208,8 @@ export default class Renderable extends Rect { * return true; * } */ - onCollision(_response, _other) { + // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars + onCollision(response, other) { // Default returns `undefined` so that bodies without a user-defined // `onCollision` get push-out by default (matches matter's "solver // resolves contacts unless `isSensor`" model). A user-defined @@ -1242,6 +1254,7 @@ export default class Renderable extends Rect { /** * Destroy function
* @ignore + * @internal */ destroy() { // allow recycling object properties diff --git a/packages/melonjs/src/renderable/sprite.js b/packages/melonjs/src/renderable/sprite.js index 26aa46d9cb..ba5bc55ef8 100644 --- a/packages/melonjs/src/renderable/sprite.js +++ b/packages/melonjs/src/renderable/sprite.js @@ -85,6 +85,10 @@ export default class Sprite extends Renderable { // accessors below) and calls back into `_applyFrame` on each frame change. // Created up front, before the texture is resolved, so the setup code can // use the accessors. + /** + * @ignore + * @internal + */ this._frameAnim = new FrameAnimation(this, (region) => { this._applyFrame(region); }); @@ -120,12 +124,14 @@ export default class Sprite extends Renderable { * backing field for the `normalMap` accessor — see the getter/setter * defined on the class for the public API and validation rules. * @ignore + * @internal */ this._normalMap = null; /** * flicker settings * @ignore + * @internal */ this._flicker = { isFlickering: false, @@ -193,6 +199,7 @@ export default class Sprite extends Renderable { /** * pause the video when losing focus * @ignore + * @internal */ this.removeStatePauseListener = on(STATE_PAUSE, () => { this.image.pause(); @@ -208,6 +215,10 @@ export default class Sprite extends Renderable { // update()/drawImage only repaint/re-upload when a frame // actually arrived. Browsers without rVFC never get the // stamp and stay on the legacy repaint-while-playing path. + /** + * @ignore + * @internal + */ this._lastVideoFrameVersion = -1; if (typeof this.image.requestVideoFrameCallback === "function") { this.image.version ??= 0; @@ -217,6 +228,10 @@ export default class Sprite extends Renderable { // `undefined++` would poison the counter with NaN // (NaN !== NaN → permanently dirty + re-uploading) this.image.version = (this.image.version ?? -1) + 1; + /** + * @ignore + * @internal + */ this._videoFrameHandle = this.image.requestVideoFrameCallback(tick); }; this._videoFrameHandle = this.image.requestVideoFrameCallback(tick); @@ -676,6 +691,7 @@ export default class Sprite extends Renderable { * Invoked by the shared {@link FrameAnimation} engine via `setRegion`. * @param {object} region - the texture region object * @ignore + * @internal */ _applyFrame(region) { // set the source texture for the given region @@ -742,6 +758,7 @@ export default class Sprite extends Renderable { /** * Returns the frame object by the index. * @ignore + * @internal * @param {number} id - the frame id * @returns {number} if using number indices. Returns {object} containing frame data if using texture atlas */ @@ -834,7 +851,6 @@ export default class Sprite extends Renderable { /** * draw this sprite (automatically called by melonJS) * @param {Renderer} renderer - a renderer instance - * @param {Camera2d} [viewport] - the viewport to (re)draw */ draw(renderer) { // do nothing if we are flickering (time-based, frame-rate independent) @@ -893,6 +909,7 @@ export default class Sprite extends Renderable { /** * Destroy function
* @ignore + * @internal */ destroy() { // release the engine's pooled `current.offset` diff --git a/packages/melonjs/src/renderable/sprite3d.js b/packages/melonjs/src/renderable/sprite3d.js index be4db56a4a..901efc7303 100644 --- a/packages/melonjs/src/renderable/sprite3d.js +++ b/packages/melonjs/src/renderable/sprite3d.js @@ -283,20 +283,34 @@ export default class Sprite3d extends Mesh { * the quad's half-width in world units (see {@link Sprite3d#billboard}). * @type {number} * @ignore + * @internal */ this._halfW = hw; - /** @ignore */ + /** + * @ignore + * @internal + */ this._halfH = hh; // local-space offset pinning `anchorPoint` to `pos` (0,0 = centered, // the default). Applied in `_applyFrame` after the flip, so mirroring // happens around the art's own center while the anchor stays fixed. - /** @ignore */ + /** + * @ignore + * @internal + */ this._anchorOffsetX = anchorOffsetX; - /** @ignore */ + /** + * @ignore + * @internal + */ this._anchorOffsetY = anchorOffsetY; // the anchor lives in the vertex data — tell Mesh.preDraw to suppress // the base transform-level anchor on BOTH camera paths (single // anchoring mechanism; see Mesh#_anchorBaked) + /** + * @ignore + * @internal + */ this._anchorBaked = true; // Repurpose the inherited anchorPoint as the LIVE anchor API (unlike // Mesh, where it stays inert on the world path): setMuted first — the @@ -309,20 +323,35 @@ export default class Sprite3d extends Mesh { // reference logical (untrimmed) frame size the world quad maps to, // captured from the first applied frame so trimmed frames can be scaled // into the same world footprint (0 = not captured yet) - /** @ignore */ + /** + * @ignore + * @internal + */ this._refLw = 0; - /** @ignore */ + /** + * @ignore + * @internal + */ this._refLh = 0; // horizontal / vertical mirror flags. Applied by mirroring the local quad // in `_applyFrame` (uniform for the billboard + fixed paths, and agnostic // to atlas rotation/trim) rather than via the inherited transform flip, // which the billboard projection doesn't use. - /** @ignore */ + /** + * @ignore + * @internal + */ this._flipX = false; - /** @ignore */ + /** + * @ignore + * @internal + */ this._flipY = false; // the last region handed to `_applyFrame`, so a flip can re-map immediately - /** @ignore */ + /** + * @ignore + * @internal + */ this._region = null; // ── frame-animation: texture refs the engine reads + the engine itself ── @@ -333,18 +362,34 @@ export default class Sprite3d extends Mesh { * @type {Function} */ this.onended = undefined; - /** the frame-aware atlas (== this.texture) @ignore */ + /** + * the frame-aware atlas (== this.texture) + * @ignore + * @internal + */ this.source = this.texture; // region dictionary + name→index map. `settings.atlas` / `atlasIndices` // (as produced by `TextureAtlas.getAnimationSettings` / // `createAnimationFromName`) take precedence so atlas-by-name animation // works exactly as it does for a 2D Sprite; otherwise fall back to the // resolved atlas's own dictionary. - /** the atlas region dictionary @ignore */ + /** + * the atlas region dictionary + * @ignore + * @internal + */ this.textureAtlas = settings.atlas ?? this.texture.getAtlas(); - /** name→index map for named-region atlases @ignore */ + /** + * name→index map for named-region atlases + * @ignore + * @internal + */ this.atlasIndices = settings.atlasIndices; - /** the shared frame-animation engine @ignore */ + /** + * the shared frame-animation engine + * @ignore + * @internal + */ this._frameAnim = new FrameAnimation(this, (region) => { this._applyFrame(region); }); @@ -373,7 +418,11 @@ export default class Sprite3d extends Mesh { */ this.billboard = settings.billboard ?? false; - /** the camera captured at draw time for the billboard projection @ignore */ + /** + * the camera captured at draw time for the billboard projection + * @ignore + * @internal + */ this._billboardCam = null; // select an initial frame: an explicit atlas region, then any predefined @@ -422,6 +471,7 @@ export default class Sprite3d extends Mesh { * bounds. Preserves the base ObservablePoint contract (updateBounds + * isDirty, see Renderable's anchorPoint callback). * @ignore + * @internal */ _onAnchorChanged() { // re-bakes the quad's corner positions in place (directly below, or @@ -674,6 +724,7 @@ export default class Sprite3d extends Mesh { * @param {number} id - the frame id * @returns {object} the frame data * @ignore + * @internal */ getAnimationFrameObjectByIndex(id) { return this._frameAnim.getAnimationFrameObjectByIndex(id); @@ -690,6 +741,7 @@ export default class Sprite3d extends Mesh { * full parity with the 2D `Sprite`. * @param {object} region - the texture region object * @ignore + * @internal */ _applyFrame(region) { // this rewrites the quad's UVs (and, for a trimmed region, its @@ -806,6 +858,7 @@ export default class Sprite3d extends Mesh { * @param {number} dt - time since the last update in milliseconds * @returns {boolean} true if the sprite changed and needs a redraw * @ignore + * @internal */ update(dt) { // advance the engine first (a frame change marks this sprite dirty via @@ -819,6 +872,7 @@ export default class Sprite3d extends Mesh { * Release resources (returns the engine's pooled `current.offset` to the * pool), then defer to the standard mesh/renderable teardown. * @ignore + * @internal */ destroy() { this._frameAnim.destroy(); @@ -835,6 +889,7 @@ export default class Sprite3d extends Mesh { * @param {CanvasRenderer|WebGLRenderer} renderer * @param {Camera2d} [viewport] * @ignore + * @internal */ draw(renderer, viewport) { this._billboardCam = viewport instanceof Camera3d ? viewport : null; @@ -845,6 +900,7 @@ export default class Sprite3d extends Mesh { * Orient the quad toward the camera when billboarding; otherwise defer to the * standard {@link Mesh} world projection (a fixed-orientation quad). * @ignore + * @internal */ _projectVerticesWorld(offsetX, offsetY, offsetZ) { if (this._billboardBasis() === false) { @@ -862,6 +918,7 @@ export default class Sprite3d extends Mesh { * can never disagree about which way the card faces. * @returns {boolean} `false` when this sprite is not billboarding * @ignore + * @internal */ _billboardBasis() { const mode = this.billboard; @@ -913,13 +970,17 @@ export default class Sprite3d extends Mesh { * Falls back to the standard mesh placement when not billboarding. * @returns {Matrix3d} the sprite's model matrix (reused instance) * @ignore + * @internal */ _composeModelMatrix() { if (this._billboardBasis() === false) { return super._composeModelMatrix(); } if (this._modelMatrix === undefined) { - /** @ignore */ + /** + * @ignore + * @internal + */ this._modelMatrix = new Matrix3d(); } const out = this._modelMatrix.val; @@ -949,6 +1010,7 @@ export default class Sprite3d extends Mesh { * offsets are the baked ±hw / ±hh quad coordinates, already shifted by the * anchor offset). Only used on renderers without retained geometry. * @ignore + * @internal */ _projectBillboardCorners(offsetX, offsetY, offsetZ) { const out = this.vertices; diff --git a/packages/melonjs/src/renderable/text/bitmaptext.js b/packages/melonjs/src/renderable/text/bitmaptext.js index 3d1b0985fa..ec969b3134 100644 --- a/packages/melonjs/src/renderable/text/bitmaptext.js +++ b/packages/melonjs/src/renderable/text/bitmaptext.js @@ -92,6 +92,8 @@ export default class BitmapText extends Renderable { /** * the text to be displayed * @private + * @ignore + * @internal */ this._text = []; @@ -149,6 +151,7 @@ export default class BitmapText extends Renderable { /** * @ignore + * @internal */ this._visibleCharacters = -1; @@ -466,6 +469,7 @@ export default class BitmapText extends Renderable { /** * Destroy function * @ignore + * @internal */ destroy() { vector2dPool.release(this.fontScale); diff --git a/packages/melonjs/src/renderable/text/bitmaptextdata.ts b/packages/melonjs/src/renderable/text/bitmaptextdata.ts index 2dcb99c207..43853ee4d0 100644 --- a/packages/melonjs/src/renderable/text/bitmaptextdata.ts +++ b/packages/melonjs/src/renderable/text/bitmaptextdata.ts @@ -34,6 +34,7 @@ const capChars: string[] = [ /** * Gets the value from a string of pairs. * @ignore + * @internal */ function getValueFromPair(string: string, pattern: RegExp): string { const value = string.match(pattern); @@ -47,6 +48,7 @@ function getValueFromPair(string: string, pattern: RegExp): string { /** * Gets the first glyph in the map that is not a space character * @ignore + * @internal * @param glyphs - the map of glyphs, each key is a char code * @returns the first glyph that is not a space character */ @@ -63,6 +65,7 @@ function getFirstGlyph(glyphs: any): Glyph | null { /** * Creates a glyph to use for the space character * @ignore + * @internal * @param glyphs - the map of glyphs, each key is a char code */ function createSpaceGlyph(glyphs: any) { @@ -154,6 +157,7 @@ export default class BitmapTextData { /** * Record a parsed glyph and fold it into the font's vertical metrics. * @ignore + * @internal */ recordGlyph(glyph: Glyph, baseLine: number) { if (glyph.width > 0 && glyph.height > 0) { @@ -171,6 +175,7 @@ export default class BitmapTextData { * Look up a glyph by char code, honestly typed as possibly missing (the * glyph map's index signature otherwise hides that a lookup can be absent). * @ignore + * @internal */ glyphFor(id: number): Glyph | undefined { return this.glyphs[id]; @@ -179,6 +184,7 @@ export default class BitmapTextData { /** * Parse the AngelCode BMFont text (.fnt) format. * @ignore + * @internal */ parseText(fontData: string) { const lines = fontData.split(/\r\n|\n/); @@ -230,6 +236,7 @@ export default class BitmapTextData { * Parse the AngelCode BMFont XML format (same data as the .fnt text form). * Padding is optional in XML exports (e.g. frostyfreeze) and defaults to 0. * @ignore + * @internal */ parseXML(fontData: string) { // Parsed with simple regex rather than DOMParser, so it also works where diff --git a/packages/melonjs/src/renderable/text/glyph.ts b/packages/melonjs/src/renderable/text/glyph.ts index 41de4bb17a..0ee2a3a0a6 100644 --- a/packages/melonjs/src/renderable/text/glyph.ts +++ b/packages/melonjs/src/renderable/text/glyph.ts @@ -4,10 +4,12 @@ const PAGE_SIZE = 1 << LOG2_PAGE_SIZE; /** * a glyph representing a single character in a font * @ignore + * @internal */ export default class Glyph { /** * @ignore + * @internal */ id: number; x: number; @@ -26,6 +28,7 @@ export default class Glyph { /** * @ignore + * @internal */ constructor() { this.id = 0; @@ -45,6 +48,7 @@ export default class Glyph { /** * @ignore + * @internal */ getKerning(ch: number): number { if (this.kerning) { @@ -58,6 +62,7 @@ export default class Glyph { /** * @ignore + * @internal */ setKerning(ch: number, value: number): void { if (!this.kerning) { diff --git a/packages/melonjs/src/renderable/text/text.js b/packages/melonjs/src/renderable/text/text.js index 4ede5eda1b..ab0b148fa3 100644 --- a/packages/melonjs/src/renderable/text/text.js +++ b/packages/melonjs/src/renderable/text/text.js @@ -162,6 +162,8 @@ export default class Text extends Renderable { /** * the text to be displayed * @private + * @ignore + * @internal */ this._text = []; @@ -169,7 +171,10 @@ export default class Text extends Renderable { this.onResetEvent(x, y, settings); } - /** @ignore */ + /** + * @ignore + * @internal + */ onResetEvent(x, y, settings) { if (typeof this.fillStyle === "undefined") { this.fillStyle = colorPool.get(0, 0, 0); @@ -240,6 +245,7 @@ export default class Text extends Renderable { /** * @ignore + * @internal */ this._visibleCharacters = -1; @@ -541,6 +547,7 @@ export default class Text extends Renderable { /** * @ignore + * @internal */ _drawFont(context, text, x, y) { setContextStyle(context, this); @@ -576,6 +583,7 @@ export default class Text extends Renderable { /** * Destroy function * @ignore + * @internal */ destroy() { const renderer = this.parentApp?.renderer ?? game.renderer; diff --git a/packages/melonjs/src/renderable/text/textstyle.js b/packages/melonjs/src/renderable/text/textstyle.js index 1b23986ae8..2eea206231 100644 --- a/packages/melonjs/src/renderable/text/textstyle.js +++ b/packages/melonjs/src/renderable/text/textstyle.js @@ -1,6 +1,7 @@ /** * apply the current text style to the given context * @ignore + * @internal */ export default function setContextStyle(context, style) { context.font = style.font; diff --git a/packages/melonjs/src/renderable/trail.js b/packages/melonjs/src/renderable/trail.js index 2cbfa6a04c..d7802f9f58 100644 --- a/packages/melonjs/src/renderable/trail.js +++ b/packages/melonjs/src/renderable/trail.js @@ -76,15 +76,30 @@ export default class Trail extends Renderable { ? options.widthCurve : [1, 0]; - /** @ignore */ + /** + * @ignore + * @internal + */ this._gradient = this._buildGradient(options); - /** @ignore */ + /** + * @ignore + * @internal + */ this._points = []; - /** @ignore */ + /** + * @ignore + * @internal + */ this._segmentColor = colorPool.get(); - /** @ignore */ + /** + * @ignore + * @internal + */ this._n0 = { x: 0, y: 0 }; - /** @ignore */ + /** + * @ignore + * @internal + */ this._n1 = { x: 0, y: 0 }; this.alwaysUpdate = true; @@ -118,7 +133,10 @@ export default class Trail extends Renderable { } } - /** @ignore */ + /** + * @ignore + * @internal + */ update(dt) { if (this.target) { const pos = this.target.pos ?? this.target; @@ -143,7 +161,10 @@ export default class Trail extends Renderable { return super.update(dt); } - /** @ignore */ + /** + * @ignore + * @internal + */ draw(renderer) { const points = this._points; const count = points.length; @@ -205,6 +226,7 @@ export default class Trail extends Renderable { * @param {object} options - trail constructor options * @returns {Gradient} * @ignore + * @internal */ _buildGradient(options) { const gradient = new Gradient("linear", [0, 0, 1, 0]); @@ -237,7 +259,10 @@ export default class Trail extends Renderable { return gradient; } - /** @ignore */ + /** + * @ignore + * @internal + */ destroy() { this._gradient.destroy(); colorPool.release(this._segmentColor); diff --git a/packages/melonjs/src/renderable/trigger.js b/packages/melonjs/src/renderable/trigger.js index 7eef62b647..003b380409 100644 --- a/packages/melonjs/src/renderable/trigger.js +++ b/packages/melonjs/src/renderable/trigger.js @@ -135,6 +135,7 @@ export default class Trigger extends Renderable { /** * @ignore + * @internal */ getTriggerSettings() { const world = this.ancestor.getRootAncestor(); diff --git a/packages/melonjs/src/renderable/ui/uibaseelement.ts b/packages/melonjs/src/renderable/ui/uibaseelement.ts index 788698ede2..a5171ee502 100644 --- a/packages/melonjs/src/renderable/ui/uibaseelement.ts +++ b/packages/melonjs/src/renderable/ui/uibaseelement.ts @@ -92,6 +92,7 @@ export default class UIBaseElement extends Container { /** * function callback for the pointerdown event * @ignore + * @internal */ clicked(event: Pointer): boolean | void { // Check if left mouse button is pressed @@ -130,6 +131,7 @@ export default class UIBaseElement extends Container { /** * function callback for the pointerEnter event * @ignore + * @internal */ enter(event: Pointer): void { this.hover = true; @@ -146,6 +148,7 @@ export default class UIBaseElement extends Container { /** * pointermove function * @ignore + * @internal */ pointerMove(event: Pointer): void { if (this.hover && !this.released) { @@ -181,6 +184,7 @@ export default class UIBaseElement extends Container { /** * function callback for the pointerLeave event * @ignore + * @internal */ leave(event: Pointer): void { this.hover = false; @@ -208,6 +212,7 @@ export default class UIBaseElement extends Container { /** * function callback for the pointerup event * @ignore + * @internal */ release(event: Pointer): boolean | void { if (!this.released) { @@ -232,6 +237,7 @@ export default class UIBaseElement extends Container { /** * function callback for the tap and hold timer event * @ignore + * @internal */ hold(): void { timer.clearTimer(this.holdTimeout); @@ -251,6 +257,7 @@ export default class UIBaseElement extends Container { /** * function called when added to the game world or a container * @ignore + * @internal */ override onActivateEvent(): void { // register pointer events @@ -277,6 +284,7 @@ export default class UIBaseElement extends Container { /** * function called when removed from the game world or a container * @ignore + * @internal */ override onDeactivateEvent(): void { // release pointer events diff --git a/packages/melonjs/src/renderable/ui/uispriteelement.ts b/packages/melonjs/src/renderable/ui/uispriteelement.ts index b152693e7b..c20fcd0c75 100644 --- a/packages/melonjs/src/renderable/ui/uispriteelement.ts +++ b/packages/melonjs/src/renderable/ui/uispriteelement.ts @@ -98,6 +98,7 @@ export default class UISpriteElement extends Sprite { /** * function callback for the pointerdown event * @ignore + * @internal */ clicked(event: Pointer): boolean | void { // Check if left mouse button is pressed @@ -132,6 +133,7 @@ export default class UISpriteElement extends Sprite { /** * function callback for the pointerEnter event * @ignore + * @internal */ enter(event: Pointer): void { this.hover = true; @@ -151,6 +153,7 @@ export default class UISpriteElement extends Sprite { /** * function callback for the pointerLeave event * @ignore + * @internal */ leave(event: Pointer): void { this.hover = false; @@ -171,6 +174,7 @@ export default class UISpriteElement extends Sprite { /** * function callback for the pointerup event * @ignore + * @internal */ release(event: Pointer): boolean | void { if (!this.released) { @@ -195,6 +199,7 @@ export default class UISpriteElement extends Sprite { /** * function callback for the tap and hold timer event * @ignore + * @internal */ hold(): void { timer.clearTimer(this.holdTimeout); @@ -214,6 +219,7 @@ export default class UISpriteElement extends Sprite { /** * function called when added to the game world or a container * @ignore + * @internal */ override onActivateEvent(): void { // register pointer events @@ -237,6 +243,7 @@ export default class UISpriteElement extends Sprite { /** * function called when removed from the game world or a container * @ignore + * @internal */ override onDeactivateEvent(): void { // release pointer events diff --git a/packages/melonjs/src/state/stage.ts b/packages/melonjs/src/state/stage.ts index 6e5dfc034b..a986a9b4c9 100644 --- a/packages/melonjs/src/state/stage.ts +++ b/packages/melonjs/src/state/stage.ts @@ -78,6 +78,7 @@ export default class Stage { * `onActivateEvent` / `onDeactivateEvent` hooks. Used by Camera2d's * ambient-overlay pass to compute the cutouts. * @ignore + * @internal */ _activeLights: Set; @@ -86,6 +87,7 @@ export default class Stage { * `onActivateEvent` / `onDeactivateEvent` hooks. Read by the lit mesh * batcher each frame to shade `lit` meshes under a `Camera3d`. * @ignore + * @internal */ _activeLights3d: Set; @@ -134,6 +136,7 @@ export default class Stage { * Called by `Light2d.onActivateEvent` to register the light with the * stage's ambient-overlay cutout list. Users normally don't call this. * @ignore + * @internal */ _registerLight(light: Light2d): void { this._activeLights.add(light); @@ -142,6 +145,7 @@ export default class Stage { /** * Called by `Light2d.onDeactivateEvent` to deregister the light. * @ignore + * @internal */ _unregisterLight(light: Light2d): void { this._activeLights.delete(light); @@ -151,6 +155,7 @@ export default class Stage { * Called by `Light3d.onActivateEvent` to register a 3D light with the stage. * Read by the lit mesh batcher. Users normally don't call this. * @ignore + * @internal */ _registerLight3d(light: Light3d): void { this._activeLights3d.add(light); @@ -159,6 +164,7 @@ export default class Stage { /** * Called by `Light3d.onDeactivateEvent` to deregister a 3D light. * @ignore + * @internal */ _unregisterLight3d(light: Light3d): void { this._activeLights3d.delete(light); @@ -167,6 +173,7 @@ export default class Stage { /** * Object reset function * @ignore + * @internal */ reset(app: Application, ...extraArgs: unknown[]): void { // Snapshot whether this is the first reset of this stage instance @@ -289,6 +296,7 @@ export default class Stage { /** * update function * @ignore + * @internal * @param dt - time since the last update in milliseconds. * @returns true if the stage needs to be redrawn */ @@ -315,6 +323,7 @@ export default class Stage { * Renderables) and the ambient overlay pass runs inside each Camera's * post-effect FBO bracket via {@link Stage#drawLighting}. * @ignore + * @internal * @param renderer - the renderer object to draw with * @param world - the world object to draw */ @@ -383,6 +392,7 @@ export default class Stage { /** * destroy function * @ignore + * @internal */ destroy(app: Application): void { // destroy the cameras this stage constructed (the fresh per-stage diff --git a/packages/melonjs/src/state/state.ts b/packages/melonjs/src/state/state.ts index adde6a8f74..dded21a0a0 100644 --- a/packages/melonjs/src/state/state.ts +++ b/packages/melonjs/src/state/state.ts @@ -54,7 +54,10 @@ const _transitionConfig: { }; // callback when state switch is done -/** @ignore */ +/** + * @ignore + * @internal + */ let _onSwitchComplete: (() => void) | null = null; // just to keep track of possible extra arguments @@ -73,6 +76,7 @@ let _freezeResolvers: Array<() => void> = []; /** * @ignore + * @internal */ function _startRunLoop(): void { // ensure nothing is running first and in valid state @@ -85,6 +89,7 @@ function _startRunLoop(): void { /** * Resume the game loop after a pause. * @ignore + * @internal */ function _resumeRunLoop(): void { // ensure game is actually paused and in valid state @@ -96,18 +101,28 @@ function _resumeRunLoop(): void { /** * Pause the loop for most stage objects. * @ignore + * @internal */ function _pauseRunLoop(): void { // Set the paused boolean to stop updates on (most) entities + /** + * @ignore + * @internal + */ _isPaused = true; } /** * Drain and resolve any pending freeze() promises. * @ignore + * @internal */ function _resolveFreezeWaiters(): void { const resolvers = _freezeResolvers; + /** + * @ignore + * @internal + */ _freezeResolvers = []; for (const resolve of resolvers) { resolve(); @@ -118,11 +133,24 @@ function _resolveFreezeWaiters(): void { * End an active freeze on timer expiry: optionally resume the run loop * (only if freeze itself performed the pause), then resolve waiters. * @ignore + * @internal */ function _endFreeze(): void { + /** + * @ignore + * @internal + */ _freezeTimer = null; + /** + * @ignore + * @internal + */ _freezeEndsAt = 0; const wasOwnedPause = _freezeStartedPause; + /** + * @ignore + * @internal + */ _freezeStartedPause = false; if (wasOwnedPause) { state.resume(_freezeMusic); @@ -134,6 +162,7 @@ function _endFreeze(): void { * Cancel any active freeze without auto-resuming (the caller is taking over * pause/resume control). Clears the timer and resolves pending waiters. * @ignore + * @internal */ function _cancelFreeze(): void { if (_freezeTimer !== null) { @@ -149,6 +178,7 @@ function _cancelFreeze(): void { * this is only called when using requestAnimFrame stuff * @param time - current timestamp in milliseconds * @ignore + * @internal */ function _renderFrame(time: number): void { emit(TICK, time); @@ -161,16 +191,22 @@ function _renderFrame(time: number): void { /** * stop the SO main loop * @ignore + * @internal */ function _stopRunLoop(): void { // cancel any previous animationRequestFrame globalThis.cancelAnimationFrame(_animFrameId); + /** + * @ignore + * @internal + */ _animFrameId = -1; } /** * start the SO main loop * @ignore + * @internal */ function _switchState(stateId: number): void { // clear previous interval if any diff --git a/packages/melonjs/src/system/device.ts b/packages/melonjs/src/system/device.ts index ed342d38f5..54b1c156bd 100644 --- a/packages/melonjs/src/system/device.ts +++ b/packages/melonjs/src/system/device.ts @@ -85,6 +85,7 @@ function hasOffscreenCanvas() { /** * used by [un]watchAccelerometer() * @ignore + * @internal */ function onDeviceMotion(e: DeviceMotionEvent) { const accel = e.accelerationIncludingGravity; @@ -99,6 +100,7 @@ function onDeviceMotion(e: DeviceMotionEvent) { /** * used by [un]watchDeviceOrientation() * @ignore + * @internal */ export function onDeviceRotate(e: DeviceOrientationEvent) { gamma = e.gamma ?? 0; @@ -328,6 +330,7 @@ export function onReady(fn: () => void) { * Called once during boot to emit BLUR/FOCUS events when the * window or tab gains/loses focus. * @ignore + * @internal */ export function initVisibilityEvents() { if (typeof globalThis.addEventListener === "function") { diff --git a/packages/melonjs/src/system/dom.ts b/packages/melonjs/src/system/dom.ts index 636808ede4..dfbe20cf55 100644 --- a/packages/melonjs/src/system/dom.ts +++ b/packages/melonjs/src/system/dom.ts @@ -6,6 +6,7 @@ import { nodeJS } from "./platform.ts"; * the callback is deferred to the next microtask. * @param fn - callback to execute when the DOM is ready * @ignore + * @internal */ export const DOMContentLoaded = (fn: () => void) => { if ( diff --git a/packages/melonjs/src/system/legacy_pool.js b/packages/melonjs/src/system/legacy_pool.js index 36658ce8c4..0f038cc69e 100644 --- a/packages/melonjs/src/system/legacy_pool.js +++ b/packages/melonjs/src/system/legacy_pool.js @@ -3,6 +3,7 @@ import { getTotalPoolSize } from "../pool"; /** * callback invoked when a class is registered, used by the Tiled object factory * @ignore + * @internal */ let onRegisterCallback = null; @@ -10,6 +11,7 @@ let onRegisterCallback = null; * Set a callback to be invoked whenever pool.register() is called. * @param {Function} callback - function(className, classObj, poolInstance) called on each registration * @ignore + * @internal */ export function setPoolRegisterCallback(callback) { onRegisterCallback = callback; diff --git a/packages/melonjs/src/system/platform.ts b/packages/melonjs/src/system/platform.ts index e12d33e561..6769b1b869 100644 --- a/packages/melonjs/src/system/platform.ts +++ b/packages/melonjs/src/system/platform.ts @@ -1,7 +1,6 @@ /** * The device platform type * @namespace platform - * @memberof device * ua the user agent string for the current device * iOS `true` if the device is an iOS platform * android `true` if the device is an Android platform diff --git a/packages/melonjs/src/system/pool.ts b/packages/melonjs/src/system/pool.ts index d29e2f88e4..8ac2a49f88 100644 --- a/packages/melonjs/src/system/pool.ts +++ b/packages/melonjs/src/system/pool.ts @@ -28,6 +28,7 @@ const pools: Record> = {}; /** * Register a pool instance to the pool registry. * @ignore + * @internal */ export const registerPool = (key: string, pool: Pool) => { pools[key] = pool; @@ -35,6 +36,7 @@ export const registerPool = (key: string, pool: Pool) => { /** * @ignore + * @internal */ export const getRegisteredPools = () => pools; diff --git a/packages/melonjs/src/system/save.ts b/packages/melonjs/src/system/save.ts index 78d6949d83..34be846577 100644 --- a/packages/melonjs/src/system/save.ts +++ b/packages/melonjs/src/system/save.ts @@ -51,6 +51,7 @@ try { /** * a function to check if the given key is a reserved word * @ignore + * @internal */ function isReserved(key: string) { return key === "add" || key === "remove"; diff --git a/packages/melonjs/src/system/timer.ts b/packages/melonjs/src/system/timer.ts index af2d7547bb..a219e2934a 100644 --- a/packages/melonjs/src/system/timer.ts +++ b/packages/melonjs/src/system/timer.ts @@ -109,6 +109,7 @@ class Timer { /** * reset time (e.g. usefull in case of pause) * @ignore + * @internal */ reset() { // set to "now" @@ -227,6 +228,7 @@ class Timer { /** * update * @ignore + * @internal */ update(time: number) { this.last = this.now; @@ -263,6 +265,7 @@ class Timer { /** * clear Timers * @ignore + * @internal */ clearTimer(timerId: number) { for (let i = 0; i < this.timers.length; i++) { @@ -276,6 +279,7 @@ class Timer { /** * update timers * @ignore + * @internal */ updateTimers() { // Iterate a SNAPSHOT. The non-repeating branch below calls diff --git a/packages/melonjs/src/tweens/tween.ts b/packages/melonjs/src/tweens/tween.ts index b92a3c333d..1de33d0da4 100644 --- a/packages/melonjs/src/tweens/tween.ts +++ b/packages/melonjs/src/tweens/tween.ts @@ -17,11 +17,20 @@ import { Interpolation, InterpolationFunction } from "./interpolation.js"; * https://github.com/tweenjs/tween.js */ -/** @ignore */ +/** + * @ignore + * @internal + */ type OnStartCallback = (this: T) => void; -/** @ignore */ +/** + * @ignore + * @internal + */ type OnUpdateCallback = (this: T, value: number) => void; -/** @ignore */ +/** + * @ignore + * @internal + */ type OnCompleteCallback = (this: T) => void; /** @@ -52,28 +61,120 @@ type OnCompleteCallback = (this: T) => void; * @category Tweens */ export default class Tween { + /** + * @ignore + * @internal + */ _object: object; + /** + * @ignore + * @internal + */ _valuesStart: Record; + /** + * @ignore + * @internal + */ _valuesEnd: Record; + /** + * @ignore + * @internal + */ _valuesStartRepeat: Record; + /** + * @ignore + * @internal + */ _duration: number; + /** + * @ignore + * @internal + */ _repeat: number; + /** + * @ignore + * @internal + */ _yoyo: boolean; + /** + * @ignore + * @internal + */ _reversed: boolean; + /** + * @ignore + * @internal + */ _delayTime: number; + /** + * @ignore + * @internal + */ _repeatDelayTime: number | undefined; + /** + * @ignore + * @internal + */ _startTime: number | null; + /** + * @ignore + * @internal + */ _easingFunction: EasingFunction; + /** + * @ignore + * @internal + */ _interpolationFunction: InterpolationFunction; + /** + * @ignore + * @internal + */ _chainedTweens: Array; + /** + * @ignore + * @internal + */ _onStartCallback: OnStartCallback | null; + /** + * @ignore + * @internal + */ _onStartCallbackFired: boolean; + /** + * @ignore + * @internal + */ _onUpdateCallback: OnUpdateCallback | null; + /** + * @ignore + * @internal + */ _onCompleteCallback: OnCompleteCallback | null; + /** + * @ignore + * @internal + */ _tweenTimeTracker: number; + /** + * @ignore + * @internal + */ _lastUpdate: number; + /** + * @ignore + * @internal + */ _isRunning: boolean; + /** + * @ignore + * @internal + */ _isPaused: boolean; + /** + * @ignore + * @internal + */ _lastTick: number; /** @@ -97,6 +198,7 @@ export default class Tween { /** * @ignore + * @internal */ onResetEvent(object: object) { this.setProperties(object); @@ -104,6 +206,7 @@ export default class Tween { /** * @ignore + * @internal */ setProperties(object: object) { // ensure any running tween is stopped before resetting (e.g., pool reuse) @@ -139,6 +242,7 @@ export default class Tween { /** * @ignore + * @internal */ _resumeCallback(elapsed: number) { this._isPaused = false; @@ -147,12 +251,18 @@ export default class Tween { } } - /** @ignore */ + /** + * @ignore + * @internal + */ _onAfterUpdate(lastUpdate: number) { this._lastUpdate = lastUpdate; } - /** @ignore */ + /** + * @ignore + * @internal + */ _onTick(timestamp: number) { if (!this._isPaused || this.updateWhenPaused) { // compute delta from the raw RAF timestamp @@ -164,12 +274,18 @@ export default class Tween { } } - /** @ignore */ + /** + * @ignore + * @internal + */ _onPause() { this._isPaused = true; } - /** @ignore */ + /** + * @ignore + * @internal + */ _onReset() { if (!this.isPersistent) { this.stop(); @@ -179,6 +295,7 @@ export default class Tween { /** * Subscribe to the game loop events * @ignore + * @internal */ _subscribe() { if (!this._isRunning) { @@ -199,6 +316,7 @@ export default class Tween { /** * Unsubscribe from the game loop events * @ignore + * @internal */ _unsubscribe() { if (this._isRunning) { @@ -435,7 +553,10 @@ export default class Tween { return this; } - /** @ignore */ + /** + * @ignore + * @internal + */ update(dt: number) { // the original Tween implementation expect // a timestamp and not a time delta diff --git a/packages/melonjs/src/utils/array-multimap.js b/packages/melonjs/src/utils/array-multimap.js index 79e43ec866..3651570ebb 100644 --- a/packages/melonjs/src/utils/array-multimap.js +++ b/packages/melonjs/src/utils/array-multimap.js @@ -1,9 +1,14 @@ /** * A simple multimap that stores multiple values per key using arrays. * @ignore + * @internal */ class ArrayMultimap { constructor() { + /** + * @ignore + * @internal + */ this._map = new Map(); } put(key, value) { diff --git a/packages/melonjs/src/utils/decode.ts b/packages/melonjs/src/utils/decode.ts index 47a0da4f9a..3717c96539 100644 --- a/packages/melonjs/src/utils/decode.ts +++ b/packages/melonjs/src/utils/decode.ts @@ -1,6 +1,7 @@ /** * the function used to decompress zlib/gzip data * @ignore + * @internal */ let inflateFunction: | ((data: string, format: string) => Uint32Array) diff --git a/packages/melonjs/src/utils/fetchdata.js b/packages/melonjs/src/utils/fetchdata.js index 63eef21e15..b30f326161 100644 --- a/packages/melonjs/src/utils/fetchdata.js +++ b/packages/melonjs/src/utils/fetchdata.js @@ -10,6 +10,7 @@ * @param {string} [protocol] - the hosting document's protocol * @returns {boolean} * @ignore + * @internal */ export function isFileProtocol(url, protocol = globalThis.location?.protocol) { return url.startsWith("file://") || protocol === "file:"; @@ -27,6 +28,7 @@ export function isFileProtocol(url, protocol = globalThis.location?.protocol) { * @param {object} settings * @returns {Promise} resolves with a `Response`-like object * @ignore + * @internal */ function fetchDataXHR(url, responseType, settings) { return new Promise((resolve, reject) => { @@ -79,6 +81,7 @@ function fetchDataXHR(url, responseType, settings) { * @param {Object} [settings] - custom settings to apply to the request (@link https://developer.mozilla.org/en-US/docs/Web/API/fetch#options) * @returns {Promise} A promise that resolves with the fetched data or rejects with an error. * @ignore + * @internal * @example * fetchData('https://api.example.com/data', 'json') * .then(data => { diff --git a/packages/melonjs/src/utils/utils.ts b/packages/melonjs/src/utils/utils.ts index 08df21c6d6..e41c47e35e 100644 --- a/packages/melonjs/src/utils/utils.ts +++ b/packages/melonjs/src/utils/utils.ts @@ -110,6 +110,7 @@ export function getUriFragment(url?: string) { * the idea here being to have a unique ID * per level / object * @ignore + * @internal */ export function resetGUID(base: string, index = 0) { // also ensure it's only 8bit ASCII characters @@ -121,6 +122,7 @@ export function resetGUID(base: string, index = 0) { * create and return a very simple GUID * Game Unique ID * @ignore + * @internal */ export function createGUID(index?: number) { // `index` is the caller's own id where it has one (a Tiled object passes diff --git a/packages/melonjs/src/video/blendmodes.js b/packages/melonjs/src/video/blendmodes.js index 78f4269419..5d26750196 100644 --- a/packages/melonjs/src/video/blendmodes.js +++ b/packages/melonjs/src/video/blendmodes.js @@ -30,6 +30,7 @@ * The array ORDER is the wire format: the index is the `uBlendMode` uniform * value the shader branches on, so reordering it silently remaps every mode. * @ignore + * @internal */ export const ADVANCED_BLEND_MODES = [ "difference", @@ -53,6 +54,7 @@ export const ADVANCED_BLEND_MODES = [ * @param {string} mode - the blend mode to test * @returns {boolean} true when the mode needs the shader path * @ignore + * @internal */ export function isAdvancedBlendMode(mode) { return ADVANCED_BLEND_MODES.indexOf(mode) !== -1; @@ -63,6 +65,7 @@ export function isAdvancedBlendMode(mode) { * @param {string} mode - the blend mode * @returns {number} the shader's mode index, or -1 when not an advanced mode * @ignore + * @internal */ export function advancedBlendModeIndex(mode) { return ADVANCED_BLEND_MODES.indexOf(mode); @@ -81,6 +84,7 @@ export function advancedBlendModeIndex(mode) { * @param {string} mode - blend mode as set through `setBlendMode` * @returns {string} the canonical token * @ignore + * @internal */ export function normalizeBlendMode(mode) { switch (mode) { @@ -104,6 +108,7 @@ export function normalizeBlendMode(mode) { * @param {string} mode - the blend mode to test * @returns {boolean} false only for a mode no backend implements * @ignore + * @internal */ export function isSupportedBlendMode(mode) { return ( @@ -124,6 +129,7 @@ export function isSupportedBlendMode(mode) { * @param {string} mode - the requested blend mode * @returns {string} the mode actually applied * @ignore + * @internal */ export function reportedBlendMode(mode) { return isSupportedBlendMode(mode) ? mode : "normal"; @@ -147,6 +153,7 @@ export function reportedBlendMode(mode) { * @returns {{operation: string, srcFactor: string, dstFactor: string}|undefined} the * blend state, or `undefined` for `"none"`, which means replace (no blending) * @ignore + * @internal */ export function blendStateFor(mode, premultipliedAlpha) { const src = premultipliedAlpha ? "one" : "src-alpha"; diff --git a/packages/melonjs/src/video/buffer/index.js b/packages/melonjs/src/video/buffer/index.js index 9294ac1ea8..a89626f361 100644 --- a/packages/melonjs/src/video/buffer/index.js +++ b/packages/melonjs/src/video/buffer/index.js @@ -3,6 +3,7 @@ * Manages a typed array of vertex indices for indexed drawing. * {@link WebGLIndexBuffer} extends this with GL-specific bind/upload operations. * @ignore + * @internal */ export default class IndexBuffer { diff --git a/packages/melonjs/src/video/buffer/vertex.js b/packages/melonjs/src/video/buffer/vertex.js index 088d9d1873..bc75be60fd 100644 --- a/packages/melonjs/src/video/buffer/vertex.js +++ b/packages/melonjs/src/video/buffer/vertex.js @@ -3,6 +3,7 @@ * Renderer-agnostic — stores vertex data in typed arrays (Float32/Uint32). * Batchers must check isFull() and flush before the buffer overflows. * @ignore + * @internal */ export default class VertexArrayBuffer { @@ -36,6 +37,7 @@ export default class VertexArrayBuffer { /** * clear the vertex array buffer * @ignore + * @internal */ clear() { this.vertexCount = 0; @@ -44,6 +46,7 @@ export default class VertexArrayBuffer { /** * return true if full * @ignore + * @internal */ isFull(vertex) { return this.vertexCount + vertex >= this.maxVertex; @@ -60,6 +63,7 @@ export default class VertexArrayBuffer { * @param {number} [textureId] - texture unit index for multi-texture batching * @param {number} [normalTextureId] - paired normal-map texture unit index, or `-1` for unlit quads * @ignore + * @internal */ push(x, y, z, u, v, tint, textureId, normalTextureId) { const offset = this.vertexCount * this.vertexSize; @@ -95,6 +99,7 @@ export default class VertexArrayBuffer { * @param {number} srcOffset - start index in the source data * @param {number} count - number of floats to copy (should equal vertexSize) * @ignore + * @internal */ pushFloats(data, srcOffset, count) { const offset = this.vertexCount * this.vertexSize; @@ -116,6 +121,7 @@ export default class VertexArrayBuffer { * bit values getting canonicalized on Metal-backed WebGL drivers. * See `mesh_batcher.init` for the rationale. * @ignore + * @internal */ pushMesh(x, y, z, u, v, tint) { const offset = this.vertexCount * this.vertexSize; @@ -140,6 +146,7 @@ export default class VertexArrayBuffer { * x, y, z, u, v, tint, nx, ny, nz. Used by the lit mesh batcher, whose * vertex layout is 12 floats (the 9 of {@link pushMesh} plus `aNormal`). * @ignore + * @internal */ pushMeshLit(x, y, z, u, v, tint, nx, ny, nz) { const offset = this.vertexCount * this.vertexSize; @@ -166,6 +173,7 @@ export default class VertexArrayBuffer { /** * return a reference to the data in Float32 format * @ignore + * @internal */ toFloat32(begin, end) { if (typeof end !== "undefined") { @@ -178,6 +186,7 @@ export default class VertexArrayBuffer { /** * return a reference to the data in Uint32 format * @ignore + * @internal */ toUint32(begin, end) { if (typeof end !== "undefined") { @@ -193,6 +202,7 @@ export default class VertexArrayBuffer { * on Float32 uploads of the same backing buffer (see the constructor's * `bufferU8` comment). * @ignore + * @internal */ toUint8(byteBegin, byteEnd) { if (typeof byteEnd !== "undefined") { diff --git a/packages/melonjs/src/video/canvas/canvas_renderer.js b/packages/melonjs/src/video/canvas/canvas_renderer.js index 05e993f505..cf2f512a84 100644 --- a/packages/melonjs/src/video/canvas/canvas_renderer.js +++ b/packages/melonjs/src/video/canvas/canvas_renderer.js @@ -105,6 +105,10 @@ export default class CanvasRenderer extends Renderer { this.clearColor(this.currentColor, this.settings.transparent !== true); // drop the per-light gradient cache; entries will lazily re-bake on // the next `drawLight()` call. + /** + * @ignore + * @internal + */ this._lightCache = undefined; } @@ -178,6 +182,10 @@ export default class CanvasRenderer extends Renderer { // OffscreenCanvas capability gating as everything else. frame = new CanvasFrameTexture(Renderer.createCanvas(w, h)); if (shared) { + /** + * @ignore + * @internal + */ this._frameTexture = frame; } } else if (frame.width !== w || frame.height !== h) { @@ -587,7 +595,15 @@ export default class CanvasRenderer extends Renderer { // `Renderer.createCanvas` for `OffscreenCanvas` / worker // safety. if (!this._meshColorCanvas) { + /** + * @ignore + * @internal + */ this._meshColorCanvas = Renderer.createCanvas(1, 1, true); + /** + * @ignore + * @internal + */ this._meshColorCtx = this._meshColorCanvas.getContext("2d"); } this._meshColorCtx.clearRect(0, 0, 1, 1); @@ -601,6 +617,10 @@ export default class CanvasRenderer extends Renderer { // pre-allocate flat sort array (reuse across frames via closure) // each entry stores: [sortKey, originalIndex] if (!this._meshSortBuf || this._meshSortBuf.length < triCount * 2) { + /** + * @ignore + * @internal + */ this._meshSortBuf = new Float64Array(triCount * 2); } const sortBuf = this._meshSortBuf; @@ -852,7 +872,7 @@ export default class CanvasRenderer extends Renderer { * @param {number} y - The y axis of the coordinate for the rectangle starting point. * @param {number} width - The rectangle's width. * @param {number} height - The rectangle's height. - * @param {number} radius - The corner radius. + * @param {number} radii - The corner radius. */ roundRect(x, y, width, height, radii) { this.getContext().roundRect(x, y, width, height, radii); @@ -1144,8 +1164,6 @@ export default class CanvasRenderer extends Renderer { * Draw a point at the specified coordinates * @param {number} x * @param {number} y - * @param {number} width - * @param {number} height */ fillPoint(x, y) { this.strokePoint(x, y); @@ -1279,6 +1297,7 @@ export default class CanvasRenderer extends Renderer { /** * @ignore + * @internal */ set lineWidth(value) { this.getContext().lineWidth = value; @@ -1296,6 +1315,7 @@ export default class CanvasRenderer extends Renderer { /** * @ignore + * @internal */ set lineJoin(value) { const context = this.getContext(); @@ -1466,6 +1486,10 @@ export default class CanvasRenderer extends Renderer { context.beginPath(); } // else use the current path + /** + * @ignore + * @internal + */ this._maskInvertOuterAdded = false; } diff --git a/packages/melonjs/src/video/canvas_factory.js b/packages/melonjs/src/video/canvas_factory.js index f0a4d4b24d..e5b18b9db5 100644 --- a/packages/melonjs/src/video/canvas_factory.js +++ b/packages/melonjs/src/video/canvas_factory.js @@ -22,6 +22,7 @@ import * as device from "../system/device.js"; * `OffscreenCanvas` if the platform supports it * @returns {HTMLCanvasElement|OffscreenCanvas} a new canvas of the given size * @ignore + * @internal */ export function createCanvas(width, height, returnOffscreenCanvas = false) { if (width === 0 || height === 0) { diff --git a/packages/melonjs/src/video/effects/blendEffect.js b/packages/melonjs/src/video/effects/blendEffect.js index 649e983097..d90803422d 100644 --- a/packages/melonjs/src/video/effects/blendEffect.js +++ b/packages/melonjs/src/video/effects/blendEffect.js @@ -111,6 +111,7 @@ fn apply(color : vec4f, uv : vec2f) -> vec4f { * activates that varying on its own. * @see {@link https://www.w3.org/TR/compositing-1/#blending} * @ignore + * @internal */ export default class BlendEffect extends ShaderEffect { /** @@ -182,6 +183,7 @@ export default class BlendEffect extends ShaderEffect { * @returns {boolean} false when the mode is not an advanced blend mode, in * which case the uniform is left untouched * @ignore + * @internal */ setBlendMode(mode) { const index = advancedBlendModeIndex(mode); diff --git a/packages/melonjs/src/video/effects/colorMatrix.js b/packages/melonjs/src/video/effects/colorMatrix.js index f864cf031c..dbf4d1e69d 100644 --- a/packages/melonjs/src/video/effects/colorMatrix.js +++ b/packages/melonjs/src/video/effects/colorMatrix.js @@ -49,6 +49,7 @@ export default class ColorMatrixEffect extends ShaderEffect { /** * the internal color matrix * @ignore + * @internal */ this._matrix = options.matrix || new ColorMatrix(); this._syncUniform(); @@ -57,6 +58,7 @@ export default class ColorMatrixEffect extends ShaderEffect { /** * Push the current matrix values to the GPU. * @ignore + * @internal */ _syncUniform() { this.setUniform("uColorMatrix", this._matrix.val); diff --git a/packages/melonjs/src/video/effects/glsl_realization.js b/packages/melonjs/src/video/effects/glsl_realization.js index 6d657733f8..641cb3308e 100644 --- a/packages/melonjs/src/video/effects/glsl_realization.js +++ b/packages/melonjs/src/video/effects/glsl_realization.js @@ -35,6 +35,7 @@ const NOISE_UV_IDENTIFIER = /\bnoise_uv\b/; * whether the body declares `name` itself (as a varying/uniform/attribute) — * the engine then leaves that identifier fully user-managed * @ignore + * @internal */ function hasOwnDeclaration(source, name) { return new RegExp( @@ -47,6 +48,7 @@ function hasOwnDeclaration(source, name) { * `: screen_texture` annotations, and detect the `screen_uv` / `noise_uv` * varyings. Bodies without builtins pass through byte-identical. * @ignore + * @internal */ function parseShaderBuiltins(fragmentBody) { const screenTextures = []; @@ -73,6 +75,7 @@ function parseShaderBuiltins(fragmentBody) { * `_setNoiseUVRect` through the `ME_*` uniforms). Built deterministically * from a template; user source is never rewritten. * @ignore + * @internal */ function buildEffectVertex(builtins) { if (!builtins.screenUV && !builtins.noiseUV) { @@ -118,6 +121,7 @@ function buildEffectVertex(builtins) { * @param {string} fragmentBody - the user body (GLSL, `vec4 apply(vec4, vec2)` convention) * @returns {{vertex: string, fragment: string, screenTextures: Array<{name: string, repeat: string}>, noiseUV: boolean}} the assembled sources + builtin usage * @ignore + * @internal */ export function buildGLSLProgram(fragmentBody) { // Shader builtins: parse & strip `: screen_texture` annotations, diff --git a/packages/melonjs/src/video/effects/radialGradient.js b/packages/melonjs/src/video/effects/radialGradient.js index cc37351461..db2d08a898 100644 --- a/packages/melonjs/src/video/effects/radialGradient.js +++ b/packages/melonjs/src/video/effects/radialGradient.js @@ -130,6 +130,10 @@ export default class RadialGradientEffect extends ShaderEffect { // reused across `setColor` calls so we don't allocate a fresh // 3-element array every frame on every light. + /** + * @ignore + * @internal + */ this._colorBuf = new Float32Array(3); const color = options.color; diff --git a/packages/melonjs/src/video/effects/shadereffect.js b/packages/melonjs/src/video/effects/shadereffect.js index 3209cd6d5f..b508ac622e 100644 --- a/packages/melonjs/src/video/effects/shadereffect.js +++ b/packages/melonjs/src/video/effects/shadereffect.js @@ -187,6 +187,7 @@ export default class ShaderEffect { * for extra samplers ({@link setTexture}), and so {@link clone} can * compile an independent copy * @ignore + * @internal */ this._renderer = renderer; @@ -195,9 +196,13 @@ export default class ShaderEffect { * {@link clone} can compile an independent copy. Stored before the * disabled-stub early return so cloning behaves consistently there too. * @ignore + * @internal */ this._fragmentBody = body; - /** @ignore */ + /** + * @ignore + * @internal + */ this._precision = precision; // resolve the body matching this renderer's shading language: a bare @@ -224,6 +229,7 @@ export default class ShaderEffect { * texture, created lazily on first draw; unused on WebGPU, where the * bind group is built lazily instead) * @ignore + * @internal */ this._extraTextures = new Map(); @@ -238,12 +244,19 @@ export default class ShaderEffect { * know when to refresh the shared frame capture before the effect draws * @type {Array<{name: string, repeat: string}>} * @ignore + * @internal */ this._screenTextureUniforms = program.screenTextures; - /** @ignore */ + /** + * @ignore + * @internal + */ this._hasNoiseUV = program.noiseUV; - /** @ignore */ + /** + * @ignore + * @internal + */ this._shader = new GLShader( renderer.gl, program.vertex, @@ -274,7 +287,10 @@ export default class ShaderEffect { ); return; } - /** @ignore */ + /** + * @ignore + * @internal + */ this.wgslRealization = realization; // same renderer-facing capture contract as the GLSL side: a // non-empty list means "refresh the frame capture before I draw" @@ -297,12 +313,20 @@ export default class ShaderEffect { on(ONCONTEXT_RESTORED, this._onContextRestored, this); } - /** @private */ + /** + * @private + * @ignore + * @internal + */ _onContextLost() { if (this.destroyed) { return; } // remember user-set state so restore doesn't override it + /** + * @ignore + * @internal + */ this._enabledBeforeSuspend = this.enabled; this.enabled = false; // GL texture handles + unit reservations are invalid after a context @@ -318,7 +342,11 @@ export default class ShaderEffect { } } - /** @private */ + /** + * @private + * @ignore + * @internal + */ _onContextRestored() { if (this.destroyed) { return; @@ -416,6 +444,7 @@ export default class ShaderEffect { * backend. A silent no-op for bodies that don't declare the uniform. * @param {number} dir - +1 (uv.y grows downward) or -1 (upward) * @ignore + * @internal */ _setUVYDir(dir) { if (this._uvYDir === dir || this.destroyed === true) { @@ -426,6 +455,10 @@ export default class ShaderEffect { !this._shader.suspended && typeof this._shader.uniforms.uUVYDir !== "undefined" ) { + /** + * @ignore + * @internal + */ this._uvYDir = dir; this._shader.setUniform("uUVYDir", dir); } else if ( @@ -450,6 +483,7 @@ export default class ShaderEffect { * @param {number} u0 - the frame's left UV coordinate (flip-normalized) * @param {number} v0 - the frame's top UV coordinate (flip-normalized) * @ignore + * @internal */ _setNoiseUVRect( sourceWidth, @@ -508,6 +542,7 @@ export default class ShaderEffect { * batcher's bind may have been skipped as redundant while the GL active * unit points elsewhere. * @ignore + * @internal */ _applyCaptureWrap(batcher, glTex, entry) { const gl = batcher.gl; @@ -655,6 +690,7 @@ export default class ShaderEffect { * bindings survive the batcher's rotating color-texture pool. * @param {object} batcher - the active batcher (owns the GL texture units) * @ignore + * @internal */ _prepareTextures(batcher) { if (!this.enabled || this._extraTextures.size === 0) { @@ -685,6 +721,10 @@ export default class ShaderEffect { // more extra textures than the batcher can hold beside // uSampler — bind what fits, warn once, skip the rest if (!this._textureOverflowWarned) { + /** + * @ignore + * @internal + */ this._textureOverflowWarned = true; console.warn( `ShaderEffect.setTexture: too many extra textures for ${batcher.maxBatchTextures} texture units — "${name}" and any later ones were not bound`, @@ -821,48 +861,72 @@ export default class ShaderEffect { // the GL-program pass-throughs below additionally guard on `_shader`: // a WGSL-realized effect is `enabled` without ever owning a GL program - /** @ignore */ + /** + * @ignore + * @internal + */ bind() { if (this.enabled && this._shader) { this._shader.bind(); } } - /** @ignore */ + /** + * @ignore + * @internal + */ getAttribLocation(name) { return this.enabled && this._shader ? this._shader.getAttribLocation(name) : -1; } - /** @ignore */ + /** + * @ignore + * @internal + */ setVertexAttributes(gl, attributes, stride) { if (this.enabled && this._shader) { this._shader.setVertexAttributes(gl, attributes, stride); } } - /** @ignore */ + /** + * @ignore + * @internal + */ get program() { return this.enabled && this._shader ? this._shader.program : null; } - /** @ignore */ + /** + * @ignore + * @internal + */ get vertex() { return this.enabled && this._shader ? this._shader.vertex : null; } - /** @ignore */ + /** + * @ignore + * @internal + */ get fragment() { return this.enabled && this._shader ? this._shader.fragment : null; } - /** @ignore */ + /** + * @ignore + * @internal + */ get attributes() { return this.enabled && this._shader ? this._shader.attributes : {}; } - /** @ignore */ + /** + * @ignore + * @internal + */ get uniforms() { return this.enabled && this._shader ? this._shader.uniforms : {}; } diff --git a/packages/melonjs/src/video/effects/wgsl/layout.js b/packages/melonjs/src/video/effects/wgsl/layout.js index 31b455171e..221f822316 100644 --- a/packages/melonjs/src/video/effects/wgsl/layout.js +++ b/packages/melonjs/src/video/effects/wgsl/layout.js @@ -13,12 +13,14 @@ * an unsupported type is a parse failure upstream (effect disables), never * a silently-wrong offset. * @ignore + * @internal */ /** * `{align, size}` per supported member type, keyed by the canonical * spelling. Aliases (`vec2` form) are normalized before lookup. * @ignore + * @internal */ const TYPE_LAYOUT = { f32: { align: 4, size: 4 }, @@ -41,6 +43,7 @@ const ARRAY_TYPE = /^array<\s*vec4f\s*,\s*(\d+)\s*>$/; * @param {string} type - a WGSL type token * @returns {string} the canonical spelling * @ignore + * @internal */ export function normalizeWGSLType(type) { return type @@ -52,6 +55,7 @@ export function normalizeWGSLType(type) { /** * round `value` up to the next multiple of `alignment` (a power of two) * @ignore + * @internal */ function roundUp(alignment, value) { return (value + alignment - 1) & ~(alignment - 1); @@ -64,6 +68,7 @@ function roundUp(alignment, value) { * the name → placement map and the total (16-byte-rounded) struct size, * or `null` when a member type is unsupported * @ignore + * @internal */ export function computeUniformLayout(members) { const map = new Map(); diff --git a/packages/melonjs/src/video/effects/wgsl/parse.js b/packages/melonjs/src/video/effects/wgsl/parse.js index cb0e8bcf24..5ba38929dc 100644 --- a/packages/melonjs/src/video/effects/wgsl/parse.js +++ b/packages/melonjs/src/video/effects/wgsl/parse.js @@ -21,6 +21,7 @@ import { computeUniformLayout } from "./layout.js"; * and disables (the generalized missing-language behavior), it never * throws and never guesses at offsets. * @ignore + * @internal */ const APPLY_FN = /\bfn\s+apply\s*\(/; @@ -37,6 +38,7 @@ const GROUP3_ANY = /@group\(\s*3\s*\)\s*@binding\(\s*(\d+)\s*\)/g; * patterns are where polynomial backtracking hides (ReDoS), and a * character scan is provably linear. * @ignore + * @internal */ function stripComments(source) { const parts = []; @@ -82,6 +84,7 @@ function stripComments(source) { * @param {string} body - the text between the struct's braces * @returns {string[]} one entry per member declaration * @ignore + * @internal */ function splitMembers(body) { const members = []; @@ -107,6 +110,7 @@ function splitMembers(body) { * or struct member of that name) — the builtin then stays user-managed, * same contract as the GLSL side * @ignore + * @internal */ function hasOwnDeclaration(source, name) { return new RegExp( @@ -120,6 +124,7 @@ function hasOwnDeclaration(source, name) { * @returns {object} `{ok: true, layout, structSize, uniformVar, textures, builtins, maxUserBinding}` * or `{ok: false, error}` * @ignore + * @internal */ export function parseWGSLBody(body) { const source = stripComments(body); diff --git a/packages/melonjs/src/video/effects/wgsl/scaffold.js b/packages/melonjs/src/video/effects/wgsl/scaffold.js index 6adbbf2d52..14aa6790cf 100644 --- a/packages/melonjs/src/video/effects/wgsl/scaffold.js +++ b/packages/melonjs/src/video/effects/wgsl/scaffold.js @@ -12,6 +12,7 @@ * - `screen_uv` is y-down (`0.5 - ndc.y * 0.5`): WebGPU texture row 0 is * the top, so the capture is sampled without any flip * @ignore + * @internal */ /** @@ -22,6 +23,7 @@ * @returns {{me: number, screenTexture: number, screenSamplerClamp: number, screenSamplerRepeat: number}} * assigned binding indices (-1 when the builtin is unused) * @ignore + * @internal */ export function assignBuiltinBindings(parsed) { let next = @@ -54,6 +56,7 @@ export function assignBuiltinBindings(parsed) { * @returns {{code: string, bindings: object}} the module text and the * builtin binding assignment (consumed when building the bind group) * @ignore + * @internal */ export function buildWGSLModule(body, parsed) { const builtins = parsed.builtins; diff --git a/packages/melonjs/src/video/effects/wgsl_realization.js b/packages/melonjs/src/video/effects/wgsl_realization.js index 2ec3a6026e..a0b79d4934 100644 --- a/packages/melonjs/src/video/effects/wgsl_realization.js +++ b/packages/melonjs/src/video/effects/wgsl_realization.js @@ -15,6 +15,7 @@ import { buildWGSLModule } from "./wgsl/scaffold.js"; * shared effect bound twice in a frame with different values stays * correct under WebGPU's queue-write-before-draws ordering. * @ignore + * @internal */ export default class WGSLEffectRealization { /** diff --git a/packages/melonjs/src/video/gpu/batcher.js b/packages/melonjs/src/video/gpu/batcher.js index df4b39d116..8cef82abd3 100644 --- a/packages/melonjs/src/video/gpu/batcher.js +++ b/packages/melonjs/src/video/gpu/batcher.js @@ -10,6 +10,7 @@ * Within the Uint16 index limit (65,535) — a deliberate capacity choice * (smaller index uploads), not an API constraint. * @ignore + * @internal */ export const DEFAULT_MAX_VERTICES = 4096; diff --git a/packages/melonjs/src/video/gpu/instancerecord.ts b/packages/melonjs/src/video/gpu/instancerecord.ts index 6be1399966..fd67b56639 100644 --- a/packages/melonjs/src/video/gpu/instancerecord.ts +++ b/packages/melonjs/src/video/gpu/instancerecord.ts @@ -22,17 +22,20 @@ import type { Matrix3d } from "../../math/matrix3d.ts"; * its `rgb` as emissive, while a custom mesh shader is free to read it as a * wind phase, an atlas offset or a random seed. * @ignore + * @internal */ /** * floats occupied by the 3×4 transform * @ignore + * @internal */ export const TRANSFORM_FLOATS = 12; /** * floats occupied by an optional `vec4` slot * @ignore + * @internal */ export const SLOT_FLOATS = 4; @@ -40,6 +43,7 @@ export const SLOT_FLOATS = 4; * Describes one instanced mesh's record: how wide it is and where each * optional slot begins. Offsets are in floats; multiply by 4 for bytes. * @ignore + * @internal */ export interface InstanceRecordLayout { /** floats per instance */ @@ -62,6 +66,7 @@ export interface InstanceRecordLayout { * @param hasData - whether a per-instance custom `vec4` slot is present * @returns the resolved layout * @ignore + * @internal */ export function instanceRecordLayout( hasColor: boolean, @@ -96,6 +101,7 @@ export function instanceRecordLayout( * @param offset - float offset of this instance's record * @param matrix - the transform to write * @ignore + * @internal */ export function writeInstanceTransform( target: Float32Array, @@ -146,6 +152,7 @@ export function writeInstanceTransform( * @param sy - scale y * @param sz - scale z * @ignore + * @internal */ export function writeInstanceTRS( target: Float32Array, @@ -199,6 +206,7 @@ export function writeInstanceTRS( * @param target - the CPU-side instance buffer * @param offset - float offset of this instance's record * @ignore + * @internal */ export function writeIdentityTransform( target: Float32Array, @@ -226,6 +234,7 @@ export function writeIdentityTransform( * @param out - the matrix to write into * @returns `out` * @ignore + * @internal */ export function readInstanceTransform( source: Float32Array, @@ -258,6 +267,7 @@ export function readInstanceTransform( * by both backends so the GL attribute records and the WGSL vertex layout * describe the same thing. * @ignore + * @internal */ export const INSTANCE_ATTRIBUTE_NAMES = { rows: ["aInstanceRow0", "aInstanceRow1", "aInstanceRow2"], @@ -275,6 +285,7 @@ export const INSTANCE_ATTRIBUTE_NAMES = { * preprocessor to renumber `@location` with — and on WebGL it keeps the two * backends describing the same thing. * @ignore + * @internal */ export const INSTANCE_SLOT_OFFSETS = { rows: [0, 1, 2], @@ -291,6 +302,7 @@ export const INSTANCE_SLOT_OFFSETS = { * locations come from the shader's own declaration order. * @returns attribute descriptors covering the whole record * @ignore + * @internal */ export function instanceAttributes( layout: InstanceRecordLayout, diff --git a/packages/melonjs/src/video/gpu/meshchunk.ts b/packages/melonjs/src/video/gpu/meshchunk.ts index bf3d9f47b0..67ed7bc517 100644 --- a/packages/melonjs/src/video/gpu/meshchunk.ts +++ b/packages/melonjs/src/video/gpu/meshchunk.ts @@ -19,6 +19,7 @@ * (or coexisting renderer) drives it, and no remap state persists across * chunks. * @ignore + * @internal */ let remapSlot = new Int32Array(0); @@ -31,6 +32,7 @@ const chunkIndices: number[] = []; * mesh with `vertexCount` vertices. Grows to the next power of two and * reuses thereafter (one-time cost when a larger mesh first appears). * @ignore + * @internal */ export function ensureRemapCapacity(vertexCount: number): void { if (remapSlot.length >= vertexCount) { @@ -48,6 +50,7 @@ export function ensureRemapCapacity(vertexCount: number): void { * (~weeks of continuous rendering away), keeping stored stamps valid. * @returns the shared chunk-index array, emptied * @ignore + * @internal */ export function beginChunk(): number[] { if (stamp >= 0x7fffffff) { @@ -63,6 +66,7 @@ export function beginChunk(): number[] { * The local index assigned to `origIdx` this chunk, or -1 when the vertex * has not been emitted yet. * @ignore + * @internal */ export function remapIndex(origIdx: number): number { return remapStamp[origIdx] === stamp ? remapSlot[origIdx] : -1; @@ -71,6 +75,7 @@ export function remapIndex(origIdx: number): number { /** * Record the local index assigned to `origIdx` for the rest of this chunk. * @ignore + * @internal */ export function assignIndex(origIdx: number, localIdx: number): void { remapStamp[origIdx] = stamp; diff --git a/packages/melonjs/src/video/gpu/meshvertex.ts b/packages/melonjs/src/video/gpu/meshvertex.ts index 78b81f0d4e..5fa65659f8 100644 --- a/packages/melonjs/src/video/gpu/meshvertex.ts +++ b/packages/melonjs/src/video/gpu/meshvertex.ts @@ -9,6 +9,7 @@ * The data deliberately carries no placement, camera or tint information — * those are uniforms — so it stays valid for the lifetime of the geometry. * @ignore + * @internal */ /** the minimal mesh surface this module reads — `@ignore` */ @@ -30,6 +31,7 @@ let buildScratch = new Float32Array(0); /** * a reusable Float32Array of at least `floatCount` floats * @ignore + * @internal */ export function retainedScratch(floatCount: number): Float32Array { if (buildScratch.length < floatCount) { @@ -46,6 +48,7 @@ export function retainedScratch(floatCount: number): Float32Array { * @param vertexSize - floats per vertex in the hosting batcher's layout * @returns number of floats written * @ignore + * @internal */ export function buildMeshVertexData( mesh: RetainedMeshSource, @@ -90,6 +93,7 @@ export function buildMeshVertexData( * @param vertexSize - floats per vertex in the hosting batcher's layout * @returns number of floats written * @ignore + * @internal */ export function buildLitMeshVertexData( mesh: RetainedMeshSource, diff --git a/packages/melonjs/src/video/gpu/primitives.ts b/packages/melonjs/src/video/gpu/primitives.ts index 7fa0493083..3f3ee67552 100644 --- a/packages/melonjs/src/video/gpu/primitives.ts +++ b/packages/melonjs/src/video/gpu/primitives.ts @@ -4,6 +4,7 @@ * precedent). The vertex layout is the primitive tier's 6-float * `x, y, z, nx, ny, packed-color` stream on both backends. * @ignore + * @internal */ /** the minimal vertex-buffer surface this module writes — `@ignore` */ @@ -39,6 +40,7 @@ interface PointLike { * primitive in 3D. For 2D matrices those slots are identity, so output * (x, y, z) is bit-identical to the legacy 2D-only multiply. * @ignore + * @internal */ export function pushPrimitiveRange( vertexData: PrimitiveVertexData, @@ -96,6 +98,7 @@ export function pushPrimitiveRange( * @param z - the current renderer depth * @param flush - drains the vertex buffer when a pair no longer fits * @ignore + * @internal */ export function expandLinesToTriangles( vertexData: PrimitiveVertexData, diff --git a/packages/melonjs/src/video/gpu/quadcorners.ts b/packages/melonjs/src/video/gpu/quadcorners.ts index e9b406e038..65d7025d85 100644 --- a/packages/melonjs/src/video/gpu/quadcorners.ts +++ b/packages/melonjs/src/video/gpu/quadcorners.ts @@ -16,6 +16,7 @@ import { Vector3d } from "../../math/vector3d.ts"; * corners are consumed before the next call, whichever backend (or * coexisting renderer) drives it. * @ignore + * @internal */ const corners = [ new Vector3d(), @@ -30,6 +31,7 @@ const corners = [ * Returns the shared corner pool, valid until the next call: * `[topLeft, topRight, bottomLeft, bottomRight]`. * @ignore + * @internal */ export function transformQuadCorners( m: Matrix3d | null | undefined, diff --git a/packages/melonjs/src/video/gpu/textureslots.js b/packages/melonjs/src/video/gpu/textureslots.js index a27ab00b72..18a2cb1400 100644 --- a/packages/melonjs/src/video/gpu/textureslots.js +++ b/packages/melonjs/src/video/gpu/textureslots.js @@ -13,6 +13,7 @@ * bind group; the caller supplies the binding through the callbacks. That keeps * it pure, so the same test suite proves both backends behave alike. * @ignore + * @internal */ export class TextureSlotTable { /** @@ -27,6 +28,7 @@ export class TextureSlotTable { * approves is held out of assignment entirely (WebGL parks `ShaderEffect` * extra samplers on high units this way). Reservations survive a reset. * @ignore + * @internal */ constructor({ capacity, onOverflow, onEvict, isReserved } = {}) { /** @type {Map} key → slot */ @@ -47,6 +49,7 @@ export class TextureSlotTable { * report an empty table while every unit was in use. * @returns {number} the number of occupied slots * @ignore + * @internal */ get size() { return this.used.size; @@ -58,6 +61,7 @@ export class TextureSlotTable { * change, where the resolved limit can differ from the previous one. * @param {number} capacity - the new slot count * @ignore + * @internal */ setCapacity(capacity) { this.capacity = capacity; @@ -84,6 +88,7 @@ export class TextureSlotTable { * @param {string} key - the slot key * @returns {number|undefined} the assigned slot, or `undefined` * @ignore + * @internal */ peek(key) { return this.slots.get(key); @@ -95,6 +100,7 @@ export class TextureSlotTable { * get an answer rather than an infinite scan. * @returns {number} a free slot index, or -1 * @ignore + * @internal */ freeSlot() { for (let slot = 0; slot < this.capacity; slot++) { @@ -118,6 +124,7 @@ export class TextureSlotTable { * cannot share a slot * @returns {number} the slot to write into the vertex stream * @ignore + * @internal */ slotFor(key) { const existing = this.slots.get(key); @@ -140,6 +147,7 @@ export class TextureSlotTable { * the mapping. Both therefore overflow on the same rule. * @returns {number} the claimed slot * @ignore + * @internal */ claim() { let slot = this.freeSlot(); @@ -168,6 +176,7 @@ export class TextureSlotTable { * @param {string} key - the slot key to release * @returns {boolean} whether the key held a slot * @ignore + * @internal */ release(key) { const slot = this.slots.get(key); @@ -184,6 +193,7 @@ export class TextureSlotTable { * Drop every assignment. `onEvict` fires once per slot that was live, so a * caller tracking bindings per slot can forget exactly those. * @ignore + * @internal */ reset() { if (this.onEvict !== undefined) { diff --git a/packages/melonjs/src/video/gpu/texturestore.js b/packages/melonjs/src/video/gpu/texturestore.js index 463129ba19..723cd04ff1 100644 --- a/packages/melonjs/src/video/gpu/texturestore.js +++ b/packages/melonjs/src/video/gpu/texturestore.js @@ -20,6 +20,7 @@ * takes its binding through callbacks. That keeps the decision logic identical * on both backends and testable without a device. * @ignore + * @internal */ export class TextureStore { /** @@ -33,6 +34,7 @@ export class TextureStore { * @param {Function} [options.onDestroy] - `(handle, source)`, release the * GPU texture. Called exactly once per handle. * @ignore + * @internal */ constructor({ onCreate, onUpload, onDestroy } = {}) { /** @type {Map} */ @@ -63,6 +65,7 @@ export class TextureStore { * @param {object} options - the resolve options * @returns {*} the new handle * @ignore + * @internal */ onCreate(source, options) { void source; @@ -79,6 +82,7 @@ export class TextureStore { * @param {object} options - the resolve options * @returns {*} a replacement handle, or nothing to keep the existing one * @ignore + * @internal */ onUpload(handle, source, record, options) { void handle; @@ -93,6 +97,7 @@ export class TextureStore { * @param {*} handle - the handle to release * @param {object} source - the source it belonged to * @ignore + * @internal */ onDestroy(handle, source) { void handle; @@ -103,6 +108,7 @@ export class TextureStore { * how many sources are currently resident * @returns {number} the record count * @ignore + * @internal */ get size() { return this.records.size; @@ -123,6 +129,7 @@ export class TextureStore { * @returns {{handle: *, version: number, generation: number, uploaded: boolean}} * the record, with `uploaded` reporting whether this call did GPU work * @ignore + * @internal */ getResidentRecord(source, options = {}) { const { version = 0, force = false } = options; @@ -165,6 +172,7 @@ export class TextureStore { * @param {object} source - the source to look up * @returns {object|undefined} the record, or `undefined` * @ignore + * @internal */ peek(source) { return this.records.get(source); @@ -177,6 +185,7 @@ export class TextureStore { * @param {object} source - the disposed source * @returns {boolean} whether a record was held * @ignore + * @internal */ destroyTexture(source) { const record = this.records.get(source); @@ -203,6 +212,7 @@ export class TextureStore { * Leave `false` for a lost context (the GPU objects are already gone); * pass `true` for an orderly teardown. * @ignore + * @internal */ releaseAll(destroy = false) { if (destroy === true) { diff --git a/packages/melonjs/src/video/gpu/topology.ts b/packages/melonjs/src/video/gpu/topology.ts index 9cbb5b2571..4042e2b2b2 100644 --- a/packages/melonjs/src/video/gpu/topology.ts +++ b/packages/melonjs/src/video/gpu/topology.ts @@ -47,6 +47,7 @@ export const PORTABLE_TOPOLOGIES = [ /** * Every accepted topology name. * @ignore + * @internal */ const TOPOLOGIES: readonly Topology[] = [ "point-list", diff --git a/packages/melonjs/src/video/gpu/vertexformat.ts b/packages/melonjs/src/video/gpu/vertexformat.ts index 4047333cec..766d6c5f6a 100644 --- a/packages/melonjs/src/video/gpu/vertexformat.ts +++ b/packages/melonjs/src/video/gpu/vertexformat.ts @@ -22,6 +22,7 @@ /** * The scalar component type underlying a {@link VertexFormat}. * @ignore + * @internal */ export type VertexScalar = | "float32" @@ -92,6 +93,7 @@ export type VertexFormat = /** * What a {@link VertexFormat} resolves to. * @ignore + * @internal */ export interface VertexFormatInfo { /** number of components (1, 2, 3 or 4) */ @@ -107,6 +109,7 @@ export interface VertexFormatInfo { /** * Bytes occupied by one component of each scalar type. * @ignore + * @internal */ const SCALAR_BYTES: Record = { float32: 4, @@ -125,6 +128,7 @@ const SCALAR_BYTES: Record = { /** * Whether a scalar type is read as a normalized fraction. * @ignore + * @internal */ const SCALAR_NORMALIZED: Record = { float32: false, @@ -147,6 +151,7 @@ const SCALAR_NORMALIZED: Record = { * @param components - how many components the attribute has * @returns the resolved format description * @ignore + * @internal */ function entry( scalar: VertexScalar, @@ -167,6 +172,7 @@ function entry( * arithmetic the GL-enum path has always used — so a layout expressed either * way produces an identical stride. * @ignore + * @internal */ export const VERTEX_FORMATS: Record = { float32: entry("float32", 1), diff --git a/packages/melonjs/src/video/gradient.js b/packages/melonjs/src/video/gradient.js index db9f6c2c7c..2d7f658284 100644 --- a/packages/melonjs/src/video/gradient.js +++ b/packages/melonjs/src/video/gradient.js @@ -15,6 +15,7 @@ import CanvasRenderTarget from "./rendertarget/canvasrendertarget.js"; * same-size texture update (the cheap path on every backend), and memory * is capped at 256 KB instead of growing with the largest gradient drawn. * @ignore + * @internal */ const GRADIENT_BAKE_SIZE = 256; @@ -22,6 +23,7 @@ const GRADIENT_BAKE_SIZE = 256; * Shared render target for GPU gradient textures. * Reused across all Gradient instances to avoid GPU memory leaks. * @ignore + * @internal */ let sharedRenderTarget = null; let sharedLastId = -1; @@ -46,7 +48,10 @@ export class Gradient { * gradient type * @type {"linear"|"radial"} */ - /** @ignore */ + /** + * @ignore + * @internal + */ this._id = nextGradientId++; this.type = type; @@ -55,6 +60,7 @@ export class Gradient { * gradient coordinates * @type {number[]} * @ignore + * @internal */ this.coords = coords; @@ -62,6 +68,7 @@ export class Gradient { * color stops * @type {Array<{offset: number, color: string}>} * @ignore + * @internal */ this.colorStops = []; @@ -69,6 +76,7 @@ export class Gradient { * cached canvas gradient (for Canvas renderer) * @type {CanvasGradient|undefined} * @ignore + * @internal */ this._canvasGradient = undefined; @@ -76,6 +84,7 @@ export class Gradient { * cached gradient render target (for WebGL renderer) * @type {CanvasRenderTarget|undefined} * @ignore + * @internal */ this._renderTarget = undefined; @@ -83,6 +92,7 @@ export class Gradient { * whether the gradient needs to be regenerated * @type {boolean} * @ignore + * @internal */ this._dirty = true; @@ -90,6 +100,7 @@ export class Gradient { * cached parsed Color objects for sampling (lazily built) * @type {{offset: number, color: Color}[]|null} * @ignore + * @internal */ this._parsedStops = null; } @@ -131,6 +142,7 @@ export class Gradient { * @param {CanvasRenderingContext2D} context - the 2D context to create the gradient on * @returns {CanvasGradient} * @ignore + * @internal */ toCanvasGradient(context) { if (this._canvasGradient && !this._dirty) { @@ -179,6 +191,7 @@ export class Gradient { * @param {number} height - draw rect height * @returns {{canvas: HTMLCanvasElement|OffscreenCanvas, width: number, height: number}} the shared gradient canvas + the used source-rect size * @ignore + * @internal */ toCanvas(renderer, x, y, width, height) { const w = Math.max(1, width); @@ -324,6 +337,7 @@ export class Gradient { /** * Build the parsed Color cache from colorStops strings. * @ignore + * @internal */ _buildParsedStops() { this._parsedStops = this.colorStops diff --git a/packages/melonjs/src/video/renderer.js b/packages/melonjs/src/video/renderer.js index 923b95d787..8a0cb9da8e 100644 --- a/packages/melonjs/src/video/renderer.js +++ b/packages/melonjs/src/video/renderer.js @@ -27,6 +27,7 @@ import CanvasRenderTarget from "./rendertarget/canvasrendertarget.js"; * entry's. One for the whole engine — the pass is never re-entered, which * `_transparentFlushing` enforces. * @ignore + * @internal */ const _savedView = new Matrix3d(); @@ -41,7 +42,6 @@ export default class Renderer { constructor(options) { /** * The renderer renderTarget - * @name renderTarget * @type {CanvasRenderTarget} */ this.renderTarget = new CanvasRenderTarget( @@ -94,6 +94,7 @@ export default class Renderer { * (GPU renderers only; ignored by Canvas renderer) * @type {GLShader|ShaderEffect|undefined} * @ignore + * @internal */ this.customShader = undefined; @@ -102,6 +103,7 @@ export default class Renderer { * Initialized by GPU renderers (WebGL, WebGPU). Null on Canvas renderer. * @type {RenderTargetPool|null} * @ignore + * @internal */ this._renderTargetPool = null; @@ -227,6 +229,7 @@ export default class Renderer { /** * @ignore + * @internal */ this.maskLevel = 0; @@ -239,6 +242,7 @@ export default class Renderer { * per draw by the mesh batchers. Null for every camera that is not a * `Camera3d` with fog enabled, which is the default. * @ignore + * @internal */ this._fog3d = null; @@ -971,6 +975,7 @@ export default class Renderer { * @param {Renderable} renderable - the renderable with postEffects to apply * @returns {boolean} false (Canvas renderer does not support post-effect processing) * @ignore + * @internal */ beginPostEffect(renderable) { // on Canvas, only set customShader for single-effect fast path @@ -991,6 +996,7 @@ export default class Renderer { * No-op on Canvas renderer. * @param {Renderable} renderable - the renderable with postEffects to apply * @ignore + * @internal */ // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars endPostEffect(renderable) {} @@ -1067,7 +1073,6 @@ export default class Renderer { * set the current blend mode. Every renderer supports the same set — * see {@link CanvasRenderer#setBlendMode} for the list and what each does. * @param {string} [mode="normal"] - blend mode - * @param {boolean} [premultipliedAlpha=true] - whether textures use premultiplied alpha */ setBlendMode(mode = "normal") { this.currentBlendMode = mode; @@ -1107,6 +1112,7 @@ export default class Renderer { * the value. * @param {object|null} [fog] - resolved fog state, or null/undefined for none * @ignore + * @internal */ setFog(fog) { this._fog3d = fog ?? null; @@ -1124,6 +1130,10 @@ export default class Renderer { (typeof lights[Symbol.iterator] === "function" && !lights[Symbol.iterator]().next().done); if (hasAny) { + /** + * @ignore + * @internal + */ this._litPipelineWarned = true; console.warn( "melonJS: Light2d normal-map lighting requires a GPU backend " + @@ -1644,7 +1654,8 @@ export default class Renderer { * @param {Rect|RoundRect|Polygon|Line|Ellipse} [mask] - the shape defining the mask to be applied * @param {boolean} [invert=false] - either the given shape should define what is visible (default) or the opposite */ - setMask() {} + // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars + setMask(mask, invert) {} /** * disable (remove) the rendering mask set through setMask. @@ -1778,4 +1789,8 @@ export default class Renderer { // Backing field for `Renderer.getWhitePixel()` — declared outside the // class body so it's initialized to null at module load (static class // fields aren't universally supported in our transpile target). +/** + * @ignore + * @internal + */ Renderer._whitePixel = null; diff --git a/packages/melonjs/src/video/renderstate.js b/packages/melonjs/src/video/renderstate.js index 5a030132b5..a3d5cc8888 100644 --- a/packages/melonjs/src/video/renderstate.js +++ b/packages/melonjs/src/video/renderstate.js @@ -78,51 +78,83 @@ export default class RenderState { /** * @ignore + * @internal */ this._stackCapacity = 32; /** * current stack depth * @ignore + * @internal */ this._stackDepth = 0; - /** @ignore */ + /** + * @ignore + * @internal + */ this._colorStack = Array.from({ length: this._stackCapacity }, () => { return new Color(); }); - /** @ignore */ + /** + * @ignore + * @internal + */ this._tintStack = Array.from({ length: this._stackCapacity }, () => { return new Color(); }); - /** @ignore */ + /** + * @ignore + * @internal + */ this._matrixStack = Array.from({ length: this._stackCapacity }, () => { return new Matrix3d(); }); - /** @ignore */ + /** + * @ignore + * @internal + */ this._scissorStack = Array.from({ length: this._stackCapacity }, () => { return new Int32Array(4); }); - /** @ignore */ + /** + * @ignore + * @internal + */ this._lineDashStack = new Array(this._stackCapacity); - /** @ignore */ + /** + * @ignore + * @internal + */ this._scissorActive = new Uint8Array(this._stackCapacity); - /** @ignore */ + /** + * @ignore + * @internal + */ this._gradientStack = new Array(this._stackCapacity); - /** @ignore */ + /** + * @ignore + * @internal + */ this._blendStack = new Array(this._stackCapacity); - /** @ignore */ + /** + * @ignore + * @internal + */ this._shaderStack = new Array(this._stackCapacity); - /** @ignore */ + /** + * @ignore + * @internal + */ this._depthStack = new Float32Array(this._stackCapacity); } @@ -173,6 +205,7 @@ export default class RenderState { * stack** — zero allocation on a hot path. Callers MUST treat it * as read-only; mutating it corrupts subsequent `restore()` calls. * @ignore + * @internal * @returns {Int32Array | null} */ peekScissor() { @@ -234,7 +267,11 @@ export default class RenderState { this.currentDepth = 0; } - /** @private — doubles stack capacity when exceeded */ + /** + * @private — doubles stack capacity when exceeded + * @ignore + * @internal + */ _growStacks() { const oldCap = this._stackCapacity; const newCap = oldCap * 2; diff --git a/packages/melonjs/src/video/rendertarget/canvasrendertarget.js b/packages/melonjs/src/video/rendertarget/canvasrendertarget.js index 2e329d4002..c0d315fb56 100644 --- a/packages/melonjs/src/video/rendertarget/canvasrendertarget.js +++ b/packages/melonjs/src/video/rendertarget/canvasrendertarget.js @@ -132,6 +132,7 @@ class CanvasRenderTarget extends RenderTarget { /** * @ignore + * @internal */ onResetEvent(width, height) { this.clear(); @@ -280,7 +281,10 @@ class CanvasRenderTarget extends RenderTarget { } } - /** @ignore */ + /** + * @ignore + * @internal + */ #invalidate(renderer) { if (renderer.type.startsWith("WebGL")) { // flush pending draws referencing the current texture data @@ -310,6 +314,7 @@ class CanvasRenderTarget extends RenderTarget { * Destroy this canvas render target and release associated GPU resources. * @param {CanvasRenderer|WebGLRenderer} [renderer] - the renderer to clean up WebGL resources from * @ignore + * @internal */ destroy(renderer) { // Look up the cached texture by SOURCE identity (the `canvas` diff --git a/packages/melonjs/src/video/rendertarget/render_target_pool.js b/packages/melonjs/src/video/rendertarget/render_target_pool.js index ee753f7a47..ef99290a65 100644 --- a/packages/melonjs/src/video/rendertarget/render_target_pool.js +++ b/packages/melonjs/src/video/rendertarget/render_target_pool.js @@ -14,21 +14,32 @@ * pairs compose like save/restore. * Render targets are lazily created and resized to match the required dimensions. * @ignore + * @internal */ export default class RenderTargetPool { /** * @param {function(number, number, boolean=): RenderTarget} factory - creates a RenderTarget with the given width and height; the third argument is `true` for CAPTURE slots (scene rasterization — may be multisampled) and `false` for ping-pong intermediates */ constructor(factory) { - /** @type {function(number, number): RenderTarget} */ + /** + * @type {function(number, number): RenderTarget} + * @ignore + * @internal + */ this._factory = factory; - /** @type {RenderTarget[]} */ + /** + * @type {RenderTarget[]} + * @ignore + * @internal + */ this._pool = []; /** * active pass bases, innermost last — a STACK, so nested begin/end * pairs unwind correctly (two scalars silently corrupted the pool on * nested passes: the inner end() popped the outer pass's slot) * @type {number[]} + * @ignore + * @internal */ this._baseStack = []; } diff --git a/packages/melonjs/src/video/rendertarget/webglrendertarget.js b/packages/melonjs/src/video/rendertarget/webglrendertarget.js index 5e71ad7269..351af57cf6 100644 --- a/packages/melonjs/src/video/rendertarget/webglrendertarget.js +++ b/packages/melonjs/src/video/rendertarget/webglrendertarget.js @@ -9,6 +9,7 @@ import RenderTarget from "./rendertarget.ts"; * - `isComplete = false` means even depth-only failed → callers should not * render into the FBO (post-effects, blits, etc. will fail) * @ignore + * @internal */ function attachDepthStencil( gl, @@ -79,6 +80,7 @@ function attachDepthStencil( * which can then be drawn to the screen through a post-process shader. * @augments RenderTarget * @ignore + * @internal */ export default class WebGLRenderTarget extends RenderTarget { /** @@ -110,6 +112,10 @@ export default class WebGLRenderTarget extends RenderTarget { this.samples = options.samples ?? 0; // the render half needs a resolve before the texture is sampled + /** + * @ignore + * @internal + */ this._needsResolve = false; // create the (resolve) framebuffer — the one whose color TEXTURE @@ -169,6 +175,7 @@ export default class WebGLRenderTarget extends RenderTarget { * Immutable storage can never be respecified, so a resize replaces the * texture object. Caller manages ACTIVE_TEXTURE save/restore. * @ignore + * @internal */ _allocateColorTexture(width, height) { const gl = this.gl; @@ -199,6 +206,7 @@ export default class WebGLRenderTarget extends RenderTarget { * Falls back to depth-only when packed depth+stencil fails; warns * once if even depth-only is incomplete. * @ignore + * @internal */ _applyDepthStencil(width, height) { const result = attachDepthStencil( @@ -209,6 +217,10 @@ export default class WebGLRenderTarget extends RenderTarget { height, this.samples, ); + /** + * @ignore + * @internal + */ this._hasStencil = result.hasStencil; if (!result.isComplete) { console.warn( diff --git a/packages/melonjs/src/video/rendertarget/webgpurendertarget.js b/packages/melonjs/src/video/rendertarget/webgpurendertarget.js index 02fdea88aa..d168c381b1 100644 --- a/packages/melonjs/src/video/rendertarget/webgpurendertarget.js +++ b/packages/melonjs/src/video/rendertarget/webgpurendertarget.js @@ -146,6 +146,7 @@ export default class WebGPURenderTarget extends RenderTarget { * lazily when the backing texture was reallocated. * @returns {GPUBindGroup} the bind group * @ignore + * @internal */ getMaterialBindGroup() { if ( diff --git a/packages/melonjs/src/video/texture/atlas.js b/packages/melonjs/src/video/texture/atlas.js index 230820d6de..99cb300979 100644 --- a/packages/melonjs/src/video/texture/atlas.js +++ b/packages/melonjs/src/video/texture/atlas.js @@ -14,6 +14,10 @@ import Texture2d from "./texture2d.ts"; // re-capture the new renderer). let _renderer; on(VIDEO_INIT, (renderer) => { + /** + * @ignore + * @internal + */ _renderer = renderer; }); @@ -25,6 +29,7 @@ on(VIDEO_INIT, (renderer) => { /** * create a simple 1 frame texture atlas based on the given parameters * @ignore + * @internal */ export function createAtlas( width, @@ -51,6 +56,7 @@ export function createAtlas( /** * return a string that identifies the texture atlas type * @ignore + * @internal */ export function identifyFormat(app) { if (app.includes("texturepacker") || app.includes("free-tex-packer")) { @@ -122,6 +128,7 @@ export class TextureAtlas extends Texture2d { /** * to identify the atlas format (e.g. texture packer) * @ignore + * @internal */ this.format = null; @@ -129,6 +136,7 @@ export class TextureAtlas extends Texture2d { * the texture source(s) itself * @type {Map} * @ignore + * @internal */ this.sources = new Map(); @@ -138,6 +146,7 @@ export class TextureAtlas extends Texture2d { * the WebGL renderer's lit pipeline for per-pixel lighting. * @type {Map} * @ignore + * @internal */ this.normalSources = new Map(); @@ -145,6 +154,7 @@ export class TextureAtlas extends Texture2d { * the atlas dictionnaries * @type {Map} * @ignore + * @internal */ this.atlases = new Map(); @@ -152,12 +162,14 @@ export class TextureAtlas extends Texture2d { * the default "active" atlas (used for multiAtlas) * @type {Map} * @ignore + * @internal */ this.activeAtlas = undefined; /** * UV lookup cache to avoid per-frame string allocation in drawImage * @ignore + * @internal */ this._uvCache = { sx: -1, sy: -1, sw: -1, sh: -1, uvs: null }; diff --git a/packages/melonjs/src/video/texture/cache.js b/packages/melonjs/src/video/texture/cache.js index 7149d1aa68..fd24671a9f 100644 --- a/packages/melonjs/src/video/texture/cache.js +++ b/packages/melonjs/src/video/texture/cache.js @@ -17,10 +17,12 @@ function normalizeRepeat(repeat) { /** * a basic texture cache object * @ignore + * @internal */ class TextureCache { /** * @ignore + * @internal */ constructor(renderer, max_size = Infinity) { // reference to the renderer that owns this cache @@ -78,6 +80,7 @@ class TextureCache { * clearing it drives the allocator directly. * @returns {Set} the occupied units * @ignore + * @internal */ get usedUnits() { return this.slotTable.used; @@ -90,6 +93,7 @@ class TextureCache { * allocator rather than leaving the two disagreeing. * @returns {number} the unit count * @ignore + * @internal */ get max_size() { return this.slotTable.capacity; @@ -101,6 +105,7 @@ class TextureCache { /** * @ignore + * @internal */ clear() { this.cache.clear(); @@ -111,6 +116,7 @@ class TextureCache { /** * @ignore + * @internal */ allocateTextureUnit() { // the policy — free-slot search skipping reservations, and flush + @@ -125,6 +131,7 @@ class TextureCache { * stays reserved until the last one releases it. * @param {number} unit - the texture unit to reserve * @ignore + * @internal */ reserveUnit(unit) { this.reservedUnits.set(unit, (this.reservedUnits.get(unit) || 0) + 1); @@ -135,6 +142,7 @@ class TextureCache { * allocatable again once its last holder releases it. * @param {number} unit - the texture unit to release * @ignore + * @internal */ releaseUnit(unit) { const count = this.reservedUnits.get(unit); @@ -149,6 +157,7 @@ class TextureCache { * Reset all texture unit assignments without clearing the texture cache. * Used by multi-texture batching when the shader's sampler range is exceeded. * @ignore + * @internal */ resetUnitAssignments() { this.units.clear(); @@ -158,6 +167,7 @@ class TextureCache { /** * @ignore + * @internal * * Frees the single `(source, repeat)` unit matching the texture's * current `repeat` field — deliberately granular, so freeing one live @@ -184,6 +194,7 @@ class TextureCache { /** * @ignore + * @internal * * Free every texture unit allocated for the texture's source, across * ALL repeat modes. A single source can hold several `(source, repeat)` @@ -204,6 +215,7 @@ class TextureCache { /** * @ignore + * @internal * @param {string} [repeat] - overrides the texture's own `repeat` for the * unit lookup — sampler state per use (a mesh's `textureRepeat`), so one * source can be sampled with several wrap modes without mutating the @@ -231,6 +243,7 @@ class TextureCache { /** * @ignore + * @internal * return every texture unit allocated for the given texture's source, * across ALL repeat modes — the unload-time counterpart of the per-use * `getUnit(texture, repeat)` override (#1503): a single source can hold @@ -246,6 +259,7 @@ class TextureCache { /** * @ignore + * @internal * return the texture unit for the given texture, or -1 if not allocated * @param {string} [repeat] - same per-use wrap override as {@link getUnit} */ @@ -260,6 +274,7 @@ class TextureCache { /** * @ignore + * @internal * cache the textureAltas for the given image */ set(image, textureAtlas) { @@ -268,6 +283,7 @@ class TextureCache { /** * @ignore + * @internal */ has(image) { return this.cache.has(image); @@ -275,6 +291,7 @@ class TextureCache { /** * @ignore + * @internal * return the textureAltas for the given image */ get(image, atlas) { @@ -316,6 +333,7 @@ class TextureCache { /** * @ignore + * @internal */ delete(image) { if (this.cache.has(image)) { @@ -339,6 +357,7 @@ class TextureCache { /** * @ignore + * @internal */ tint(src, color) { // make sure the src is in the cache diff --git a/packages/melonjs/src/video/texture/frametexture.js b/packages/melonjs/src/video/texture/frametexture.js index c7cf5385ae..73bb9f0fe7 100644 --- a/packages/melonjs/src/video/texture/frametexture.js +++ b/packages/melonjs/src/video/texture/frametexture.js @@ -14,6 +14,7 @@ import Texture2d from "./texture2d.ts"; * static copy. * @augments Texture2d * @ignore + * @internal */ export class FrameTexture extends Texture2d { /** @@ -23,6 +24,10 @@ export class FrameTexture extends Texture2d { */ constructor(renderer, width, height) { super(); + /** + * @ignore + * @internal + */ this._renderer = renderer; /** @type {number} */ this.width = width; @@ -71,6 +76,7 @@ export class FrameTexture extends Texture2d { * CPU-side reuse (e.g. drawing the captured frame back onto the scene). * @augments Texture2d * @ignore + * @internal */ export class CanvasFrameTexture extends Texture2d { /** diff --git a/packages/melonjs/src/video/texture/noise_texture2d.js b/packages/melonjs/src/video/texture/noise_texture2d.js index a9b1d95496..f98ef7a5ef 100644 --- a/packages/melonjs/src/video/texture/noise_texture2d.js +++ b/packages/melonjs/src/video/texture/noise_texture2d.js @@ -106,11 +106,23 @@ class NoiseTexture2d extends Texture2d { /** the current animation time (third sampling axis) @type {number} */ this.time = 0; - /** the baked output canvas (reused across re-bakes) @type {HTMLCanvasElement|null} @ignore */ + /** + * the baked output canvas (reused across re-bakes) @type {HTMLCanvasElement|null} + * @ignore + * @internal + */ this._canvas = null; - /** reused ImageData scratch (avoids a per-bake allocation) @type {ImageData|null} @ignore */ + /** + * reused ImageData scratch (avoids a per-bake allocation) @type {ImageData|null} + * @ignore + * @internal + */ this._imageData = null; - /** reused height-field scratch (avoids a per-bake allocation) @type {Float32Array|null} @ignore */ + /** + * reused height-field scratch (avoids a per-bake allocation) @type {Float32Array|null} + * @ignore + * @internal + */ this._heights = null; /** content revision, bumped on every bake and stamped on the canvas so * the renderer re-uploads the GPU texture when it changes @type {number} @ignore */ @@ -193,6 +205,7 @@ class NoiseTexture2d extends Texture2d { * decoupled from the spatial frequency (otherwise low-frequency textures * would animate imperceptibly slowly). * @ignore + * @internal */ _rawNoise(x, y) { if (!this.animated) { @@ -206,6 +219,7 @@ class NoiseTexture2d extends Texture2d { * x-axis seamless blend: in the right skirt band, cross-fade toward the * wrapped (period-shifted) sample so the left and right edges meet. * @ignore + * @internal */ _blendX(x, y, w, sk) { const base = this._rawNoise(x, y); @@ -222,6 +236,7 @@ class NoiseTexture2d extends Texture2d { * with a much-reduced seam. * @returns {Float32Array} the per-pixel height field (length `width*height`) * @ignore + * @internal */ _buildHeightField() { const w = this.width; @@ -265,7 +280,10 @@ class NoiseTexture2d extends Texture2d { return heights; } - /** @ignore */ + /** + * @ignore + * @internal + */ _writeGrayscale(data, heights) { for (let i = 0; i < heights.length; i++) { const c = Math.round(heights[i] * 255); @@ -277,7 +295,10 @@ class NoiseTexture2d extends Texture2d { } } - /** @ignore */ + /** + * @ignore + * @internal + */ _writeColorRamp(data, heights) { const ramp = this.colorRamp; const color = new Color(); @@ -296,6 +317,7 @@ class NoiseTexture2d extends Texture2d { * flipped to normal-map Y-up so it round-trips through the lit shader's * `rgb * 2 - 1` decode. Neighbor samples wrap when `seamless`. * @ignore + * @internal */ _writeNormalMap(data, heights) { const w = this.width; diff --git a/packages/melonjs/src/video/texture/parser/aseprite.js b/packages/melonjs/src/video/texture/parser/aseprite.js index 524e7f3e83..2e154c2d8a 100644 --- a/packages/melonjs/src/video/texture/parser/aseprite.js +++ b/packages/melonjs/src/video/texture/parser/aseprite.js @@ -7,6 +7,7 @@ import { Vector2d } from "../../../math/vector2d.ts"; * @param {TextureAtlas} textureAtlas - the texture atlas class calling the parser * @returns {Object} the corresponding Atlas * @ignore + * @internal */ export function parseAseprite(data, textureAtlas) { const atlas = {}; diff --git a/packages/melonjs/src/video/texture/parser/spritesheet.js b/packages/melonjs/src/video/texture/parser/spritesheet.js index aa40c1e3dc..e4f36453b5 100644 --- a/packages/melonjs/src/video/texture/parser/spritesheet.js +++ b/packages/melonjs/src/video/texture/parser/spritesheet.js @@ -6,6 +6,7 @@ import { Vector2d, vector2dPool } from "../../../math/vector2d.ts"; * @param {TextureAtlas} textureAtlas - the texture atlas class calling the parser * @returns {Object} the corresponding Atlas * @ignore + * @internal */ export function parseSpriteSheet(data, textureAtlas) { const atlas = {}; diff --git a/packages/melonjs/src/video/texture/parser/texturepacker.js b/packages/melonjs/src/video/texture/parser/texturepacker.js index f48ea94320..b74547192c 100644 --- a/packages/melonjs/src/video/texture/parser/texturepacker.js +++ b/packages/melonjs/src/video/texture/parser/texturepacker.js @@ -7,6 +7,7 @@ import { Vector2d } from "../../../math/vector2d.ts"; * @param {TextureAtlas} textureAtlas - the texture atlas class calling the parser * @returns {Object} the corresponding Atlas * @ignore + * @internal */ export function parseTexturePacker(data, textureAtlas) { const atlas = {}; diff --git a/packages/melonjs/src/video/texture/resource.js b/packages/melonjs/src/video/texture/resource.js index 0669f7759b..5c6a662282 100644 --- a/packages/melonjs/src/video/texture/resource.js +++ b/packages/melonjs/src/video/texture/resource.js @@ -61,6 +61,7 @@ export class TextureResource { * For a resource this is the resource itself — `createTexture2D` * dispatches to `resource.upload(context, target)`. * @ignore + * @internal */ getTexture() { return this; @@ -122,7 +123,10 @@ export class BufferTextureResource extends TextureResource { this.format = options.format || "rgba8"; } - /** @ignore */ + /** + * @ignore + * @internal + */ upload(context, target) { if (this.format === "rgba8ui") { // `RGBA8UI` / `RGBA_INTEGER` are WebGL 2-only enums. On a diff --git a/packages/melonjs/src/video/texture/texture2d.ts b/packages/melonjs/src/video/texture/texture2d.ts index 0e10bc0dfd..e53b6d81a4 100644 --- a/packages/melonjs/src/video/texture/texture2d.ts +++ b/packages/melonjs/src/video/texture/texture2d.ts @@ -3,6 +3,7 @@ import { emit, TEXTURE2D_DESTROYED } from "../../system/event.ts"; /** * Compile-time-only brand key; no runtime value can hold it. * @ignore + * @internal */ declare const gpuResidentBrand: unique symbol; @@ -23,6 +24,7 @@ export interface GPUResidentTexture { /** * Phantom nominal brand — never present at runtime. * @ignore + * @internal */ readonly [gpuResidentBrand]: true; } diff --git a/packages/melonjs/src/video/utils/autodetect.js b/packages/melonjs/src/video/utils/autodetect.js index e4f45d592e..b8015030a5 100644 --- a/packages/melonjs/src/video/utils/autodetect.js +++ b/packages/melonjs/src/video/utils/autodetect.js @@ -35,6 +35,7 @@ const BACKEND_CANDIDATES = [ /** * Auto-detect the best renderer to use * @ignore + * @internal */ export function autoDetectRenderer(options) { let lastError; diff --git a/packages/melonjs/src/video/webgl/batchers/batcher.js b/packages/melonjs/src/video/webgl/batchers/batcher.js index abc42f3867..de5ac68f0b 100644 --- a/packages/melonjs/src/video/webgl/batchers/batcher.js +++ b/packages/melonjs/src/video/webgl/batchers/batcher.js @@ -29,6 +29,7 @@ export class WebGLBatcher extends Batcher { * disagree. * @type {Topology} * @ignore + * @internal */ #topology = "triangle-list"; @@ -36,6 +37,7 @@ export class WebGLBatcher extends Batcher { * The GL enum for `#topology`, precomputed so reads stay cheap. * @type {number} * @ignore + * @internal */ #mode = 4; @@ -185,6 +187,7 @@ export class WebGLBatcher extends Batcher { * the GL vertex buffer object (own buffer for indexed batchers, null for shared) * @type {WebGLBuffer|null} * @ignore + * @internal */ this.glVertexBuffer = null; @@ -192,6 +195,7 @@ export class WebGLBatcher extends Batcher { * the dynamic index buffer (only for indexed batchers) * @type {WebGLIndexBuffer|null} * @ignore + * @internal */ this.indexBuffer = null; @@ -215,6 +219,7 @@ export class WebGLBatcher extends Batcher { * shared one. * @type {WebGLBuffer} * @ignore + * @internal */ get uploadBuffer() { return this.glVertexBuffer ?? this.renderer.vertexBuffer; @@ -230,6 +235,7 @@ export class WebGLBatcher extends Batcher { * layout, in layout order (see {@link validateShaderLocations}) — the * locations are frozen here at the default shader's mapping. * @ignore + * @internal */ createVertexState() { const descriptor = { @@ -256,6 +262,7 @@ export class WebGLBatcher extends Batcher { * {@link WebGLRenderer#destroy}; subclasses that override must chain to * `super.destroy()`. * @ignore + * @internal */ destroy() { const gl = this.gl; @@ -281,6 +288,7 @@ export class WebGLBatcher extends Batcher { /** * Reset batcher internal state * @ignore + * @internal */ reset() { // WebGL context @@ -354,6 +362,7 @@ export class WebGLBatcher extends Batcher { * declare a prefix of the batcher's attribute layout, in layout order. * A mismatched shader silently reads wrong vertex data — warn loudly. * @ignore + * @internal */ validateShaderLocations(shader) { if (this.validatedShaders === undefined) { @@ -394,6 +403,7 @@ export class WebGLBatcher extends Batcher { * happened and costs two loads otherwise. Called by every flush path * (the base and the quad override). * @ignore + * @internal */ syncProgram() { const shader = this.currentShader; @@ -561,6 +571,7 @@ export class WebGLBatcher extends Batcher { * @param {number} argCount - how many arguments the caller actually passed * @returns {object} a `{name, format?, size?, type?, normalized?, offset?}` descriptor * @ignore + * @internal */ #toAttributeDescriptor(name, size, type, normalized, offset, argCount) { if (typeof name === "object" && name !== null) { @@ -593,6 +604,7 @@ export class WebGLBatcher extends Batcher { * @param {object} descriptor - the normalized descriptor * @returns {object} `{name, format, size, type, normalized, offset, bytes}` * @ignore + * @internal */ #resolveAttribute(descriptor) { const { name } = descriptor; @@ -669,6 +681,7 @@ export class WebGLBatcher extends Batcher { * @param {GLenum} type - component type * @returns {number} bytes occupied * @ignore + * @internal */ #byteSizeOf(size, type) { switch (type) { diff --git a/packages/melonjs/src/video/webgl/batchers/lit_mesh_batcher.js b/packages/melonjs/src/video/webgl/batchers/lit_mesh_batcher.js index bee555e45f..1bf8ff603d 100644 --- a/packages/melonjs/src/video/webgl/batchers/lit_mesh_batcher.js +++ b/packages/melonjs/src/video/webgl/batchers/lit_mesh_batcher.js @@ -42,6 +42,7 @@ export default class LitMeshBatcher extends MeshBatcher { * than `reset` while the context is invalid), so the previous block — * whose GL name belonged to the dead context — is dropped first. * @ignore + * @internal */ init(renderer) { super.init(renderer); @@ -53,16 +54,25 @@ export default class LitMeshBatcher extends MeshBatcher { * {@link LitMeshBatcher#updatePassState}. * @type {UniformBlock} * @ignore + * @internal */ // Claim a binding point once and hold it: `init()` re-runs on context // restore, and claiming again each time would walk through the // device's budget over a long session. + /** + * @ignore + * @internal + */ this._bindingPoint ??= renderer.reserveUniformBindingPoint(); this.lightBlock = new UniformBlock( renderer.gl, BLOCK3D_FLOATS, this._bindingPoint, ); + /** + * @ignore + * @internal + */ this._lightBlockProgram = null; // see the note in LitQuadBatcher.init: an active-but-unbound uniform // block makes the program undrawable, so bind it at birth rather than @@ -79,6 +89,7 @@ export default class LitMeshBatcher extends MeshBatcher { * transition. Comparing against the program we last bound covers all * three — a pointer compare in the steady state. * @ignore + * @internal */ _bindLightBlock() { const shader = this.currentShader || this.defaultShader; @@ -90,7 +101,11 @@ export default class LitMeshBatcher extends MeshBatcher { this.lightBlock.bindTo(program, "Light3dBlock"); } - /** release the light block along with the rest. @ignore */ + /** + * release the light block along with the rest. + * @ignore + * @internal + */ destroy() { this.lightBlock?.destroy(); this.lightBlock = undefined; @@ -98,7 +113,11 @@ export default class LitMeshBatcher extends MeshBatcher { super.destroy(); } - /** add the world-space normal attribute on top of the base layout. @ignore */ + /** + * add the world-space normal attribute on top of the base layout. + * @ignore + * @internal + */ _attributeLayout(renderer) { // the parameter is kept for the subclass contract even though a // format-declared layout no longer needs a rendering context @@ -113,7 +132,11 @@ export default class LitMeshBatcher extends MeshBatcher { return attributes; } - /** use the lit (half-Lambert) shader. @ignore */ + /** + * use the lit (half-Lambert) shader. + * @ignore + * @internal + */ _shaderSources() { return { vertex: litVertex, fragment: litFragmentResolved }; } @@ -124,12 +147,17 @@ export default class LitMeshBatcher extends MeshBatcher { * `#ifdef`-guarded, so the two programs differ only by the defines the * variant is compiled with, and the lighting loop exists in one place. * @ignore + * @internal */ _instancedShaderSources() { return { vertex: litInstancedVertex, fragment: litFragmentResolved }; } - /** push the 12-float lit vertex, appending the mesh's world-space normal. @ignore */ + /** + * push the 12-float lit vertex, appending the mesh's world-space normal. + * @ignore + * @internal + */ _pushVertex(vertexData, x, y, z, u, v, color, mesh, i3) { const n = mesh.normals; vertexData.pushMeshLit( @@ -152,6 +180,7 @@ export default class LitMeshBatcher extends MeshBatcher { * @param {Float32Array} out - destination scratch * @returns {number} number of floats written * @ignore + * @internal */ buildRetainedVertexData(mesh, out) { // the shared neutral builder (zero-normal guard included) — one @@ -180,6 +209,7 @@ export default class LitMeshBatcher extends MeshBatcher { * keeps a `lit` mesh fullbright — matching the unlit path — while an * ambient-only scene still uses its real ambient. * @ignore + * @internal */ updatePassState() { super.updatePassState(); diff --git a/packages/melonjs/src/video/webgl/batchers/lit_quad_batcher.js b/packages/melonjs/src/video/webgl/batchers/lit_quad_batcher.js index 4ea7204283..1ee48d8285 100644 --- a/packages/melonjs/src/video/webgl/batchers/lit_quad_batcher.js +++ b/packages/melonjs/src/video/webgl/batchers/lit_quad_batcher.js @@ -35,6 +35,7 @@ import QuadBatcher from "./quad_batcher.js"; export default class LitQuadBatcher extends QuadBatcher { /** * @ignore + * @internal */ init(renderer) { // One shared pool, same size as the unlit batcher's (#1585). This used @@ -100,6 +101,7 @@ export default class LitQuadBatcher extends QuadBatcher { * needs (re-)uploading, mirroring the color-texture cache. * @type {Array} * @ignore + * @internal */ this.boundNormalMaps = new Array(pool).fill(null); @@ -110,6 +112,7 @@ export default class LitQuadBatcher extends QuadBatcher { * to know when to re-bind/re-upload. `-1` = nothing bound. * @type {number[]} * @ignore + * @internal */ this.boundNormalVersions = new Array(pool).fill(-1); @@ -128,6 +131,7 @@ export default class LitQuadBatcher extends QuadBatcher { * `destroy()` releases the previous instance first, so nothing leaks. * @type {TextureStore} * @ignore + * @internal */ this.normalStore?.releaseAll(); this.normalStore = new WebGLTextureStore(this.gl); @@ -139,11 +143,24 @@ export default class LitQuadBatcher extends QuadBatcher { * while the unit itself comes from the same allocator the colors use. * @type {Map} * @ignore + * @internal */ this.normalUnits = new Map(); + /** + * @ignore + * @internal + */ this._cacheEpoch = 0; + /** + * @ignore + * @internal + */ this._lightCount = 0; + /** + * @ignore + * @internal + */ this._maxLights = MAX_LIGHTS; // `init` is re-run on context restore (WebGLRenderer.reset), against a @@ -157,16 +174,25 @@ export default class LitQuadBatcher extends QuadBatcher { * program bound — a buffer upload is independent of `useProgram`. * @type {UniformBlock} * @ignore + * @internal */ // Claim a binding point once and hold it: `init()` re-runs on context // restore, and claiming again each time would walk through the // device's budget over a long session. + /** + * @ignore + * @internal + */ this._bindingPoint ??= renderer.reserveUniformBindingPoint(); this.lightBlock = new UniformBlock( renderer.gl, BLOCK_FLOATS, this._bindingPoint, ); + /** + * @ignore + * @internal + */ this._lightBlockProgram = null; // Bind immediately rather than waiting for the first activation. An // active-but-unbound uniform block is INVALID_OPERATION at draw time, @@ -189,6 +215,7 @@ export default class LitQuadBatcher extends QuadBatcher { * Unsubscribe the `TEXTURE2D_DESTROYED` listener; delegates to * `MaterialBatcher.destroy()` for the texture-cache-reset one. * @ignore + * @internal */ destroy() { if (this._onTexture2dDestroyed) { @@ -210,6 +237,7 @@ export default class LitQuadBatcher extends QuadBatcher { * `toFrameTexture` claim. Normal maps now go through the shared allocator * like everything else, so there is nothing to hold back. * @ignore + * @internal */ bind() { super.bind(); @@ -229,6 +257,7 @@ export default class LitQuadBatcher extends QuadBatcher { * block, so `bindTo` reports failure and we simply record it, leaving the * next real lit program to bind normally. * @ignore + * @internal */ _bindLightBlock() { const shader = this.currentShader || this.defaultShader; @@ -261,6 +290,7 @@ export default class LitQuadBatcher extends QuadBatcher { /** * @ignore + * @internal */ reset() { // QuadBatcher.reset rebuilds the index buffer, rebinds color @@ -297,6 +327,7 @@ export default class LitQuadBatcher extends QuadBatcher { * skips re-binding, and samples the clobbering texture as a normal map. * @param {number} unit - the GL texture unit to invalidate * @ignore + * @internal */ invalidateUnit(unit) { super.invalidateUnit(unit); @@ -322,6 +353,7 @@ export default class LitQuadBatcher extends QuadBatcher { * color texture. The `?.` guards a reset firing before `init` allocates the * arrays (none does today; hardens against future init reordering). * @ignore + * @internal */ _onTextureCacheReset() { super._onTextureCacheReset(); @@ -419,6 +451,7 @@ export default class LitQuadBatcher extends QuadBatcher { * came and went, until something forced a full reset. * @param {HTMLImageElement|HTMLCanvasElement|OffscreenCanvas|ImageBitmap} image - normal-map source * @ignore + * @internal */ releaseNormalUnit(image) { const unit = this.normalUnits?.get(image); @@ -445,6 +478,7 @@ export default class LitQuadBatcher extends QuadBatcher { * @param {HTMLImageElement|HTMLCanvasElement|OffscreenCanvas|ImageBitmap} normalMap - the source * @returns {number} the slot to write into `aNormalTextureId` * @ignore + * @internal */ resolveNormalUnit(normalMap) { const version = normalMap.version ?? 0; diff --git a/packages/melonjs/src/video/webgl/batchers/material_batcher.js b/packages/melonjs/src/video/webgl/batchers/material_batcher.js index d0d2709bf0..1d9eeaffc9 100644 --- a/packages/melonjs/src/video/webgl/batchers/material_batcher.js +++ b/packages/melonjs/src/video/webgl/batchers/material_batcher.js @@ -18,6 +18,7 @@ import { WebGLBatcher } from "./batcher.js"; * deleted textures drop their records with them. * @type {WeakMap} * @ignore + * @internal */ const immutableStorage = new WeakMap(); @@ -25,6 +26,7 @@ const immutableStorage = new WeakMap(); * full mip chain length for a base size (immutable storage allocates the * whole pyramid up front) * @ignore + * @internal */ function mipLevels(w, h) { return Math.floor(Math.log2(Math.max(w, h))) + 1; @@ -34,6 +36,7 @@ export class MaterialBatcher extends WebGLBatcher { /** * Initialize the textured batcher * @ignore + * @internal */ init(renderer, settings) { super.init(renderer, settings); @@ -45,6 +48,7 @@ export class MaterialBatcher extends WebGLBatcher { /** * bound textures by unit * @ignore + * @internal */ this.boundTextures = []; @@ -57,12 +61,14 @@ export class MaterialBatcher extends WebGLBatcher { * Text / gradient re-bake never re-allocates. * @type {Set} * @ignore + * @internal */ this.dirtyUnits = new Set(); /** * track the current sampler unit to avoid redundant gl.uniform1i calls * @ignore + * @internal */ this.currentSamplerUnit = -1; @@ -82,6 +88,10 @@ export class MaterialBatcher extends WebGLBatcher { if (!this._onCacheReset) { // delegate to an overridable method so subclasses that track extra // per-unit bindings (lit normal maps) can drop those on a reset too + /** + * @ignore + * @internal + */ this._onCacheReset = () => { this._onTextureCacheReset(); }; @@ -96,6 +106,7 @@ export class MaterialBatcher extends WebGLBatcher { * forget those too; without that they'd assume the extra texture is still * resident and skip re-binding it after the reset. * @ignore + * @internal */ _onTextureCacheReset() { this.boundTextures.length = 0; @@ -115,6 +126,7 @@ export class MaterialBatcher extends WebGLBatcher { * video frames after a mesh pass. * @type {number} * @ignore + * @internal */ get currentTextureUnit() { return this.renderer._activeTextureUnit; @@ -130,6 +142,7 @@ export class MaterialBatcher extends WebGLBatcher { * accumulating handlers (relevant on context loss / renderer * teardown). * @ignore + * @internal */ destroy() { if (this._onCacheReset) { @@ -142,6 +155,7 @@ export class MaterialBatcher extends WebGLBatcher { /** * Reset batcher internal state * @ignore + * @internal */ reset() { super.reset(); @@ -425,6 +439,7 @@ export class MaterialBatcher extends WebGLBatcher { * {@link MaterialBatcher#unbindTexture2D}. * @param {number} unit - the texture unit whose content is stale * @ignore + * @internal */ markTextureDirty(unit) { this.dirtyUnits.add(unit); @@ -454,6 +469,7 @@ export class MaterialBatcher extends WebGLBatcher { * too. * @param {number} unit - the GL texture unit to invalidate * @ignore + * @internal */ invalidateUnit(unit) { delete this.boundTextures[unit]; @@ -464,6 +480,7 @@ export class MaterialBatcher extends WebGLBatcher { /** * @ignore + * @internal * @param {TextureAtlas|TextureResource} texture * @param {number} [w] - ignored when the source has its own `width` (the * common case); kept for the legacy signature where callers passed a diff --git a/packages/melonjs/src/video/webgl/batchers/mesh_batcher.js b/packages/melonjs/src/video/webgl/batchers/mesh_batcher.js index df853b1a7c..c0cc6847ce 100644 --- a/packages/melonjs/src/video/webgl/batchers/mesh_batcher.js +++ b/packages/melonjs/src/video/webgl/batchers/mesh_batcher.js @@ -90,6 +90,7 @@ export default class MeshBatcher extends MaterialBatcher { /** * Initialize the mesh batcher * @ignore + * @internal */ init(renderer) { super.init(renderer, { @@ -216,6 +217,7 @@ export default class MeshBatcher extends MaterialBatcher { * `aVertex` (3) + `aRegion` (2) + `aColor` (4) = 9 floats. Subclasses * (e.g. {@link LitMeshBatcher}) append their own attributes. * @ignore + * @internal */ _attributeLayout(_renderer) { return [ @@ -249,6 +251,7 @@ export default class MeshBatcher extends MaterialBatcher { * The shader sources for this batcher (unlit by default). Subclasses * override to supply a lit shader. * @ignore + * @internal */ _shaderSources() { return { vertex: meshVertex, fragment: meshFragment }; @@ -263,6 +266,7 @@ export default class MeshBatcher extends MaterialBatcher { * with the built-in one on this batcher (e.g. `drawMesh` swapping a custom * shader in and back out). * @ignore + * @internal */ useShader(shader) { if ( @@ -293,6 +297,7 @@ export default class MeshBatcher extends MaterialBatcher { * renderer teardown). Delegates to `MaterialBatcher.destroy()` for * the texture-cache-reset listener. * @ignore + * @internal */ destroy() { // variants hold GL programs AND stay subscribed to the context-loss @@ -316,6 +321,7 @@ export default class MeshBatcher extends MaterialBatcher { * referencing the old ones would draw from freed memory. Meshes rebuild * lazily on their next draw. * @ignore + * @internal */ reset() { this.releaseAllRetained(); @@ -370,6 +376,7 @@ export default class MeshBatcher extends MaterialBatcher { * clears it, so this batcher being current implies a writable depth buffer, * without which `gl.clear(DEPTH_BUFFER_BIT)` would silently do nothing. * @ignore + * @internal */ updatePassState() { if (this.renderer._meshDepthDirty) { @@ -407,6 +414,7 @@ export default class MeshBatcher extends MaterialBatcher { * @param {object} _mesh - the source mesh (unused here; for subclasses) * @param {number} _i3 - the source vertex's `index * 3` (for subclasses) * @ignore + * @internal */ _pushVertex(vertexData, x, y, z, u, v, color, _mesh, _i3) { vertexData.pushMesh(x, y, z, u, v, color); @@ -441,6 +449,7 @@ export default class MeshBatcher extends MaterialBatcher { * @param {Matrix3d} modelMatrix - the mesh's own placement, or identity when its vertices are already positioned * @param {number} tint - tint colour in UINT32 (argb) format * @ignore + * @internal */ /** * Write one mesh's model-space geometry into `out` in this batcher's @@ -453,6 +462,7 @@ export default class MeshBatcher extends MaterialBatcher { * @param {Float32Array} out - destination scratch, at least `vertexCount × vertexSize` long * @returns {number} number of floats written * @ignore + * @internal */ buildRetainedVertexData(mesh, out) { // the shared neutral builder — one copy for both backends @@ -465,6 +475,7 @@ export default class MeshBatcher extends MaterialBatcher { * @param {object} mesh - the mesh whose geometry is wanted * @returns {RetainedGeometry} up-to-date geometry for the mesh * @ignore + * @internal */ retainedGeometryFor(mesh) { let geometry = this.retained.get(mesh); @@ -502,6 +513,7 @@ export default class MeshBatcher extends MaterialBatcher { * @param {Matrix3d} modelMatrix - where the mesh sits in the world * @param {number} tint - tint colour in UINT32 (argb) format * @ignore + * @internal */ drawRetainedMesh(mesh, modelMatrix, tint) { const gl = this.gl; @@ -592,6 +604,7 @@ export default class MeshBatcher extends MaterialBatcher { * last 2D draw left, and under `"additive"` a dark shadow would *brighten* * the ground. * @ignore + * @internal */ beginBlendedDraw(mode = "normal") { // straight through the renderer's tables rather than the cached @@ -615,6 +628,7 @@ export default class MeshBatcher extends MaterialBatcher { * `setBlendMode` with the cache invalidated restores both, and leaves the * cache reading exactly what it read before. * @ignore + * @internal */ endBlendedDraw() { const gl = this.gl; @@ -641,6 +655,7 @@ export default class MeshBatcher extends MaterialBatcher { * @param {InstancedMesh} mesh - the mesh to draw * @returns {object} `{geometry, instances, vertexState}` * @ignore + * @internal */ instancedStateFor(mesh) { const gl = this.gl; @@ -736,6 +751,7 @@ export default class MeshBatcher extends MaterialBatcher { * @param {object} layout - the instance record layout * @returns {GLShader} the shader for that combination * @ignore + * @internal */ instancedShaderFor(layout) { const fogDefine = this._fogDefine(); @@ -772,6 +788,7 @@ export default class MeshBatcher extends MaterialBatcher { * Compiling it out means a scene that never enables fog runs the shader it * ran before fog existed, instruction for instruction. * @ignore + * @internal */ _fogDefine() { return this.renderer._fog3d !== null && this.renderer._fog3d !== undefined @@ -795,6 +812,7 @@ export default class MeshBatcher extends MaterialBatcher { * always the same set, since some flags never reach the fragment stage * @returns {GLShader} the program for that combination * @ignore + * @internal */ shaderVariant(key, sources, vertexDefines, fragmentDefines) { let shader = this.shaderVariants.get(key); @@ -819,6 +837,7 @@ export default class MeshBatcher extends MaterialBatcher { * swapping unconditionally threw that away silently. * @returns {boolean} true when the swap is safe * @ignore + * @internal */ _ownsCurrentShader() { return ( @@ -831,6 +850,7 @@ export default class MeshBatcher extends MaterialBatcher { * The non-instanced mesh shader for the current fog state: the batcher's * own program while fog is off, a fog variant while it is on. * @ignore + * @internal */ meshShader() { const fogDefine = this._fogDefine(); @@ -849,6 +869,7 @@ export default class MeshBatcher extends MaterialBatcher { * The instanced shader sources for this batcher (unlit by default). * Subclasses override to supply the lit pair. * @ignore + * @internal */ _instancedShaderSources() { return { vertex: meshInstancedVertex, fragment: meshFragment }; @@ -861,6 +882,7 @@ export default class MeshBatcher extends MaterialBatcher { * @param {object} layout - the instance record layout * @returns {object[]} attribute records * @ignore + * @internal */ _instanceAttributeRecords(layout) { const gl = this.gl; @@ -886,6 +908,7 @@ export default class MeshBatcher extends MaterialBatcher { * @param {Matrix3d} modelMatrix - where the group sits in the world * @param {number} tint - tint colour in UINT32 (argb) format * @ignore + * @internal */ drawInstancedMesh(mesh, modelMatrix, tint) { const gl = this.gl; @@ -985,6 +1008,7 @@ export default class MeshBatcher extends MaterialBatcher { * from getting coloured, glowing shadows. * @returns {GLShader} the shadow program * @ignore + * @internal */ instancedShadowShader() { const fogDefine = this._fogDefine(); @@ -1019,6 +1043,7 @@ export default class MeshBatcher extends MaterialBatcher { * @param {object} quadGeometry - the shared shadow quad's retained geometry * @returns {object} the per-mesh instanced state, with `shadowVertexState` built * @ignore + * @internal */ instancedShadowStateFor(mesh, quadGeometry) { // Deliberately NOT `instancedStateFor`. That one keys its staleness on @@ -1094,6 +1119,7 @@ export default class MeshBatcher extends MaterialBatcher { * @param {number} tint - tint colour in UINT32 (argb) format * @param {object} quad - the shared shadow quad mesh * @ignore + * @internal */ drawInstancedShadow(mesh, shadowMatrix, tint, quad) { const gl = this.gl; @@ -1129,6 +1155,7 @@ export default class MeshBatcher extends MaterialBatcher { * Release the instance buffer and vertex state held for one mesh, if any. * @param {object} mesh - the mesh whose instance state should be freed * @ignore + * @internal */ releaseInstanced(mesh) { const state = this.instanced?.get(mesh); @@ -1143,6 +1170,7 @@ export default class MeshBatcher extends MaterialBatcher { /** * Release every instance buffer this batcher holds. * @ignore + * @internal */ releaseAllInstanced() { this.instanced?.forEach((state) => { @@ -1157,6 +1185,7 @@ export default class MeshBatcher extends MaterialBatcher { * Release the retained geometry held for one mesh, if any. * @param {object} mesh - the mesh whose geometry should be freed * @ignore + * @internal */ releaseRetained(mesh) { this.releaseInstanced(mesh); @@ -1170,6 +1199,7 @@ export default class MeshBatcher extends MaterialBatcher { /** * Release every retained geometry this batcher holds. * @ignore + * @internal */ releaseAllRetained() { this.releaseAllInstanced(); @@ -1190,6 +1220,7 @@ export default class MeshBatcher extends MaterialBatcher { * as "the model vanished" rather than as an error, so say so explicitly. * @param {GLShader} shader - the shader about to be hosted * @ignore + * @internal */ validateShaderLocations(shader) { const firstTime = @@ -1339,6 +1370,7 @@ export default class MeshBatcher extends MaterialBatcher { * property of the mesh, not of the material group. * @returns {number} the texture unit the material landed on * @ignore + * @internal */ applyMeshMaterial(mesh, texture = mesh.texture) { // upload and activate the texture. The mesh's own `textureRepeat` @@ -1515,6 +1547,7 @@ export default class MeshBatcher extends MaterialBatcher { * unknown name. * @param {number} unit - the texture unit to sample from * @ignore + * @internal */ bindSamplerUnit(unit) { if ( @@ -1561,6 +1594,7 @@ export default class MeshBatcher extends MaterialBatcher { * @param {number} from - first index to accumulate * @param {number} length - how many indices to accumulate * @ignore + * @internal */ accumulateRange(mesh, from, length) { const vertices = mesh.vertices; diff --git a/packages/melonjs/src/video/webgl/batchers/primitive_batcher.js b/packages/melonjs/src/video/webgl/batchers/primitive_batcher.js index 213a125e5c..71680f3d80 100644 --- a/packages/melonjs/src/video/webgl/batchers/primitive_batcher.js +++ b/packages/melonjs/src/video/webgl/batchers/primitive_batcher.js @@ -21,6 +21,7 @@ export default class PrimitiveBatcher extends WebGLBatcher { /** * Initialize the compositor * @ignore + * @internal */ init(renderer) { super.init(renderer, { @@ -52,6 +53,7 @@ export default class PrimitiveBatcher extends WebGLBatcher { /** * the current line width applied to the shader uniform * @ignore + * @internal */ this.currentLineWidth = 1; } @@ -73,6 +75,7 @@ export default class PrimitiveBatcher extends WebGLBatcher { /** * Reset compositor internal state * @ignore + * @internal */ reset() { super.reset(); @@ -148,6 +151,7 @@ export default class PrimitiveBatcher extends WebGLBatcher { * Push `verts[start..end)` into the vertex buffer, transformed by the * current view matrix. The caller guarantees the range fits. * @ignore + * @internal */ #pushRange(verts, start, end, colorUint32, z) { // the shared neutral range push (z-column-aware transform) — one @@ -176,6 +180,7 @@ export default class PrimitiveBatcher extends WebGLBatcher { * flip triangle winding at a boundary — irrelevant here, the primitive * pipeline never enables face culling.) * @ignore + * @internal */ #drawVerticesChunked(mode, verts, vertexCount, colorUint32, z) { const gl = this.gl; @@ -246,6 +251,7 @@ export default class PrimitiveBatcher extends WebGLBatcher { * @param {Point[]} verts - line vertices in pairs [from, to, from, to, ...] * @param {number} vertexCount - number of vertices * @ignore + * @internal */ #expandLinesToTriangles(verts, vertexCount) { // switch to TRIANGLES mode, then delegate the expansion to the diff --git a/packages/melonjs/src/video/webgl/batchers/quad_batcher.js b/packages/melonjs/src/video/webgl/batchers/quad_batcher.js index 7ead77a74d..baeb09a0ff 100644 --- a/packages/melonjs/src/video/webgl/batchers/quad_batcher.js +++ b/packages/melonjs/src/video/webgl/batchers/quad_batcher.js @@ -19,12 +19,14 @@ export default class QuadBatcher extends MaterialBatcher { /** * Initialize the compositor * @ignore + * @internal */ init(renderer) { /** * the maximum number of texture units used for multi-texture batching * @type {number} * @ignore + * @internal */ // the full pool the renderer resolved (#1585). The 16 that used to cap // this was the WebGL 2 spec FLOOR for MAX_TEXTURE_IMAGE_UNITS — safe @@ -71,6 +73,7 @@ export default class QuadBatcher extends MaterialBatcher { * (disabled when a custom ShaderEffect is applied) * @type {boolean} * @ignore + * @internal */ this.useMultiTexture = true; @@ -81,6 +84,7 @@ export default class QuadBatcher extends MaterialBatcher { * (Re-)create the index buffer for quad batching (4 verts + 6 indices per quad). * Called from `init` and `reset` (after context loss). * @ignore + * @internal */ createIndexBuffer() { // The ELEMENT_ARRAY_BUFFER binding is vertex-state state, so the @@ -107,6 +111,7 @@ export default class QuadBatcher extends MaterialBatcher { * Bind the color sampler uniforms (`uSampler0..uSamplerN-1`) to their * respective texture units. Called from `init` and `reset`. * @ignore + * @internal */ bindColorSamplers() { for (let i = 0; i < this.maxBatchTextures; i++) { @@ -130,6 +135,7 @@ export default class QuadBatcher extends MaterialBatcher { /** * Reset compositor internal state * @ignore + * @internal */ reset() { super.reset(); diff --git a/packages/melonjs/src/video/webgl/buffer/index.js b/packages/melonjs/src/video/webgl/buffer/index.js index 5ab61c5100..6b12a6b97e 100644 --- a/packages/melonjs/src/video/webgl/buffer/index.js +++ b/packages/melonjs/src/video/webgl/buffer/index.js @@ -3,6 +3,7 @@ import IndexBuffer from "../../buffer/index.js"; /** * A WebGL Index Buffer — extends {@link IndexBuffer} with GL buffer binding and upload. * @ignore + * @internal */ export default class WebGLIndexBuffer extends IndexBuffer { diff --git a/packages/melonjs/src/video/webgl/buffer/instance_buffer.js b/packages/melonjs/src/video/webgl/buffer/instance_buffer.js index 7e0b83fd68..14db5c258f 100644 --- a/packages/melonjs/src/video/webgl/buffer/instance_buffer.js +++ b/packages/melonjs/src/video/webgl/buffer/instance_buffer.js @@ -14,6 +14,7 @@ * count, so growing by one instance does not reallocate on the GPU until the * CPU-side array itself grows. * @ignore + * @internal */ export default class WebGLInstanceBuffer { /** diff --git a/packages/melonjs/src/video/webgl/buffer/retained_geometry.js b/packages/melonjs/src/video/webgl/buffer/retained_geometry.js index 1c04b70db7..4f0d66ed9f 100644 --- a/packages/melonjs/src/video/webgl/buffer/retained_geometry.js +++ b/packages/melonjs/src/video/webgl/buffer/retained_geometry.js @@ -16,6 +16,7 @@ import WebGLVertexState from "./vertexstate.js"; * `Float32Array` itself: some drivers canonicalize NaN bit patterns on a * float upload, which would corrupt packed values. See `VertexArrayBuffer`. * @ignore + * @internal */ export default class RetainedGeometry { /** @@ -173,6 +174,7 @@ export default class RetainedGeometry { /** * Whether a plain index array needs 32-bit indices. * @ignore + * @internal */ function vertexDataExceedsUint16(indices) { for (let i = 0; i < indices.length; i++) { diff --git a/packages/melonjs/src/video/webgl/buffer/uniformblock.js b/packages/melonjs/src/video/webgl/buffer/uniformblock.js index a4671b6b95..d1b71c448b 100644 --- a/packages/melonjs/src/video/webgl/buffer/uniformblock.js +++ b/packages/melonjs/src/video/webgl/buffer/uniformblock.js @@ -22,6 +22,7 @@ * buffer itself needs no recovery hook — the renderer re-runs each batcher's * `init()` on restore, which releases this block and builds a new one. * @ignore + * @internal */ export default class UniformBlock { /** @@ -42,13 +43,23 @@ export default class UniformBlock { * mirror of what was last uploaded, so an unchanged frame can skip the * `bufferSubData` entirely * @type {Float32Array} + * @ignore + * @internal */ this._uploaded = new Float32Array(floats); - /** nothing has been uploaded yet, so the mirror is not yet valid */ + /** + * nothing has been uploaded yet, so the mirror is not yet valid + * @ignore + * @internal + */ this._everUploaded = false; - /** live length of the last upload; -1 until there has been one */ + /** + * live length of the last upload; -1 until there has been one + * @ignore + * @internal + */ this._uploadedLength = -1; /** @type {number} */ @@ -120,6 +131,7 @@ export default class UniformBlock { * @param {number} floats - length of the live prefix * @returns {boolean} true when an upload would be a no-op * @ignore + * @internal */ #matches(floats) { if (this._uploadedLength !== floats) { diff --git a/packages/melonjs/src/video/webgl/buffer/vertexstate.js b/packages/melonjs/src/video/webgl/buffer/vertexstate.js index 0e0d43dd54..55b3710acd 100644 --- a/packages/melonjs/src/video/webgl/buffer/vertexstate.js +++ b/packages/melonjs/src/video/webgl/buffer/vertexstate.js @@ -8,6 +8,7 @@ * @param {object} descriptor - the descriptor to read * @returns {object[]} buffer layout groups * @ignore + * @internal */ function bufferGroups(descriptor) { if (Array.isArray(descriptor.buffers)) { @@ -48,6 +49,7 @@ function bufferGroups(descriptor) { * disturb whichever one is mid-frame. Callers never touch * `bindVertexArray` directly. * @ignore + * @internal */ export default class WebGLVertexState { /** @@ -79,6 +81,7 @@ export default class WebGLVertexState { * bookkeeping — a WebGPU backend builds immutable descriptors and has * no global binding points to disturb. * @ignore + * @internal */ #captureBindings() { const gl = this.gl; @@ -88,7 +91,10 @@ export default class WebGLVertexState { }; } - /** @ignore */ + /** + * @ignore + * @internal + */ #restoreBindings(saved) { const gl = this.gl; gl.bindVertexArray(saved.vertexArray); diff --git a/packages/melonjs/src/video/webgl/glshader.js b/packages/melonjs/src/video/webgl/glshader.js index 3004463226..cf00737afa 100644 --- a/packages/melonjs/src/video/webgl/glshader.js +++ b/packages/melonjs/src/video/webgl/glshader.js @@ -134,6 +134,10 @@ export default class GLShader { // per-host WGSL family registrations for the current device // generation: {epoch, keys: Map} — compared // against the pipeline cache's epoch so a device loss re-registers + /** + * @ignore + * @internal + */ this._wgslRegistrations = { epoch: -1, keys: new Map() }; if (!this.isWebGL && !this.isWebGPU) { @@ -181,11 +185,27 @@ export default class GLShader { this.suspended = false; // raw source kept so we can recompile against a restored context + /** + * @ignore + * @internal + */ this._sourceVertex = vertex; + /** + * @ignore + * @internal + */ this._sourceFragment = fragment; + /** + * @ignore + * @internal + */ this._precision = precision; // uniform writes are cached + replayed across a context cycle + /** + * @ignore + * @internal + */ this._uniformCache = Object.create(null); if (this.isWebGL) { @@ -216,6 +236,8 @@ export default class GLShader { * {@link _onContextRestored}. Replays any cached uniform values * against the freshly-extracted uniforms proxy. * @private + * @ignore + * @internal */ _compile() { this.vertex = setPrecision( @@ -266,6 +288,8 @@ export default class GLShader { * but preserves the shader source + cached uniform values so the * shader can be transparently rebuilt on context restore. * @private + * @ignore + * @internal */ _onContextLost() { if (this.destroyed || this.suspended) { @@ -290,6 +314,8 @@ export default class GLShader { * re-links the shader against the new GL context, then replays * any cached uniform values via {@link _compile}. * @private + * @ignore + * @internal */ _onContextRestored() { if (this.destroyed) { @@ -483,6 +509,7 @@ export default class GLShader { * `get`, or null when the module failed validation on this device * generation (the host then uses its built-in family) * @ignore + * @internal */ registerWGSL(cache, host, bindGroupLayouts, vertexLayoutKey) { // epoch first, invalid-gate second: a device loss replaces the cache diff --git a/packages/melonjs/src/video/webgl/lighting/pack3d.ts b/packages/melonjs/src/video/webgl/lighting/pack3d.ts index 080911fbf3..b75be4cdc4 100644 --- a/packages/melonjs/src/video/webgl/lighting/pack3d.ts +++ b/packages/melonjs/src/video/webgl/lighting/pack3d.ts @@ -4,6 +4,7 @@ import { MAX_LIGHTS } from "./constants.ts"; /** * Uniform-ready packing of the active 3D lights for the mesh-lit shader. * @ignore + * @internal */ export interface PackedMeshLighting { /** number of active shaded lights, clamped to `MAX_LIGHTS`. */ @@ -60,6 +61,7 @@ const _result: PackedMeshLighting = { * @param lights - iterable of lights, or `null`/`undefined` (treated as empty) * @returns the packed lighting (reused instance) * @ignore + * @internal */ export function packMeshLights( lights: Iterable | null | undefined, diff --git a/packages/melonjs/src/video/webgl/lighting/std140.ts b/packages/melonjs/src/video/webgl/lighting/std140.ts index 29ee0af709..30c5ebcdf2 100644 --- a/packages/melonjs/src/video/webgl/lighting/std140.ts +++ b/packages/melonjs/src/video/webgl/lighting/std140.ts @@ -33,6 +33,7 @@ import { MAX_LIGHTS } from "./constants.ts"; /** * floats per `vec4`, the block's fundamental unit * @ignore + * @internal */ const VEC4 = 4; @@ -49,24 +50,28 @@ const VEC4 = 4; * and float members means the staging buffer can no longer be a single * `Float32Array` view, and the cast is free on every GPU that matters. * @ignore + * @internal */ export const HEADER_FLOATS = VEC4 * 2; /** * floats occupied by one light: two `vec4`s * @ignore + * @internal */ export const LIGHT_FLOATS = VEC4 * 2; /** * total floats in a light block, header included * @ignore + * @internal */ export const BLOCK_FLOATS = HEADER_FLOATS + MAX_LIGHTS * LIGHT_FLOATS; /** * total bytes in a light block * @ignore + * @internal */ export const BLOCK_BYTES = BLOCK_FLOATS * Float32Array.BYTES_PER_ELEMENT; @@ -76,6 +81,7 @@ export const BLOCK_BYTES = BLOCK_FLOATS * Float32Array.BYTES_PER_ELEMENT; * @param count - number of live lights * @param ambient - ambient colour, 0..1 per channel * @ignore + * @internal */ function writeHeader( out: Float32Array, @@ -112,6 +118,7 @@ function writeHeader( * @param packed.ambient - `[r, g, b]` ambient floor; absent means black * @returns how many floats of `out` are live, for a partial upload * @ignore + * @internal */ export function writeLight2dBlock( out: Float32Array, @@ -164,18 +171,21 @@ export function writeLight2dBlock( * + range + direction + both cone cosines + color, which cannot fold into * two vec4s' padding. The 2D block keeps its two-vec4 stride. * @ignore + * @internal */ export const LIGHT3D_FLOATS = VEC4 * 3; /** * total floats in a 3D light block, header included * @ignore + * @internal */ export const BLOCK3D_FLOATS = HEADER_FLOATS + MAX_LIGHTS * LIGHT3D_FLOATS; /** * total bytes in a 3D light block * @ignore + * @internal */ export const BLOCK3D_BYTES = BLOCK3D_FLOATS * Float32Array.BYTES_PER_ELEMENT; @@ -206,6 +216,7 @@ export const BLOCK3D_BYTES = BLOCK3D_FLOATS * Float32Array.BYTES_PER_ELEMENT; * @param packed.ambient - `[r, g, b]` ambient floor; absent means black * @returns how many floats of `out` are live, for a partial upload * @ignore + * @internal */ export function writeLight3dBlock( out: Float32Array, diff --git a/packages/melonjs/src/video/webgl/renderers/tmxlayer/orthogonal.js b/packages/melonjs/src/video/webgl/renderers/tmxlayer/orthogonal.js index b08c037d29..c09702efcc 100644 --- a/packages/melonjs/src/video/webgl/renderers/tmxlayer/orthogonal.js +++ b/packages/melonjs/src/video/webgl/renderers/tmxlayer/orthogonal.js @@ -37,6 +37,7 @@ const DEFAULT_TINT = new Float32Array([1, 1, 1, 1]); * triggers). * * @ignore + * @internal */ export default class OrthogonalTMXLayerGPURenderer { /** @@ -72,7 +73,15 @@ export default class OrthogonalTMXLayerGPURenderer { this.animLookups = new Map(); // pre-allocated scratch for uniform uploads — avoids per-frame // allocation in the hot path + /** + * @ignore + * @internal + */ this._v2 = new Float32Array(2); + /** + * @ignore + * @internal + */ this._v4 = new Float32Array(4); } @@ -81,6 +90,7 @@ export default class OrthogonalTMXLayerGPURenderer { * resource map. Called from `WebGLRenderer.reset()` (which * `GAME_RESET` triggers) so each level transition starts clean. * @ignore + * @internal */ reset() { // Uploads happen via the quad batcher (see `_drawLayer`), so pin @@ -126,6 +136,8 @@ export default class OrthogonalTMXLayerGPURenderer { * @param {number} x * @param {number} y * @private + * @ignore + * @internal */ _setV2(name, x, y) { this._v2[0] = x; @@ -141,6 +153,8 @@ export default class OrthogonalTMXLayerGPURenderer { * @param {number} z * @param {number} w * @private + * @ignore + * @internal */ _setV4(name, x, y, z, w) { this._v4[0] = x; @@ -168,6 +182,8 @@ export default class OrthogonalTMXLayerGPURenderer { * (`atlasCols * atlasRows`) * @returns {{resource: BufferTextureResource, data: Uint8Array, * tileCount: number, dirty: boolean}|undefined} + * @ignore + * @internal */ _getOrUpdateAnimLookup(tileset, tileCount) { if (!tileset.isAnimated || tileset.animations.size === 0) { @@ -220,6 +236,8 @@ export default class OrthogonalTMXLayerGPURenderer { * Get-or-create the per-layer index `BufferTextureResource`. * @param {TMXLayer} layer * @returns {BufferTextureResource} + * @ignore + * @internal */ _getResource(layer) { let resource = this.resources.get(layer); diff --git a/packages/melonjs/src/video/webgl/shaders/multitexture-lit.js b/packages/melonjs/src/video/webgl/shaders/multitexture-lit.js index b5b9771cc5..13e6fab936 100644 --- a/packages/melonjs/src/video/webgl/shaders/multitexture-lit.js +++ b/packages/melonjs/src/video/webgl/shaders/multitexture-lit.js @@ -6,6 +6,7 @@ import { MAX_LIGHTS } from "../lighting/constants.ts"; * array is forbidden in GLSL ES 3.00 exactly as it was in 1.00, so this * stays an if-ladder using the usual `< i + 0.5` threshold pattern. * @ignore + * @internal */ function buildSamplerSelect(varName, samplerPrefix, count, target) { const lines = []; @@ -51,6 +52,7 @@ function buildSamplerSelect(varName, samplerPrefix, count, target) { * @param {number} maxTextures - the number of color/normal texture units to support * @returns {string} GLSL fragment shader source * @ignore + * @internal */ export function buildLitMultiTextureFragment(maxTextures) { const count = Math.max(maxTextures, 1); diff --git a/packages/melonjs/src/video/webgl/shaders/multitexture.js b/packages/melonjs/src/video/webgl/shaders/multitexture.js index 81dd9e95e7..30c6738c8b 100644 --- a/packages/melonjs/src/video/webgl/shaders/multitexture.js +++ b/packages/melonjs/src/video/webgl/shaders/multitexture.js @@ -5,6 +5,7 @@ * @param {number} maxTextures - the number of texture units to support * @returns {string} GLSL fragment shader source * @ignore + * @internal */ export function buildMultiTextureFragment(maxTextures) { const count = Math.max(maxTextures, 1); diff --git a/packages/melonjs/src/video/webgl/texture/store.js b/packages/melonjs/src/video/webgl/texture/store.js index 28a95c8ddb..45da713df0 100644 --- a/packages/melonjs/src/video/webgl/texture/store.js +++ b/packages/melonjs/src/video/webgl/texture/store.js @@ -14,11 +14,13 @@ import { TextureStore } from "./../../gpu/texturestore.js"; * their handles are that batcher's to own, but the policy is identical. * @augments TextureStore * @ignore + * @internal */ export class WebGLTextureStore extends TextureStore { /** * @param {WebGL2RenderingContext} gl - the owning context * @ignore + * @internal */ constructor(gl) { super(); @@ -28,6 +30,7 @@ export class WebGLTextureStore extends TextureStore { /** * @returns {WebGLTexture} a fresh texture object * @ignore + * @internal */ onCreate() { return this.gl.createTexture(); @@ -48,6 +51,7 @@ export class WebGLTextureStore extends TextureStore { * @returns {WebGLTexture} the handle actually used, which may be a * replacement when immutable storage had to be respecified * @ignore + * @internal */ onUpload(handle, source, record, options) { return options.upload(handle); @@ -56,6 +60,7 @@ export class WebGLTextureStore extends TextureStore { /** * @param {WebGLTexture} handle - the texture object to release * @ignore + * @internal */ onDestroy(handle) { this.gl.deleteTexture(handle); diff --git a/packages/melonjs/src/video/webgl/utils/attributes.js b/packages/melonjs/src/video/webgl/utils/attributes.js index ca5b476bdc..78e75ac297 100644 --- a/packages/melonjs/src/video/webgl/utils/attributes.js +++ b/packages/melonjs/src/video/webgl/utils/attributes.js @@ -7,6 +7,7 @@ * form leaves the shader with no bound vertex data and the rasterizer * silently degenerates every triangle. * @ignore + * @internal */ export function extractAttributes(gl, shader) { const attributes = {}; diff --git a/packages/melonjs/src/video/webgl/utils/maxtextures.js b/packages/melonjs/src/video/webgl/utils/maxtextures.js index 9458d6bf33..50d069ad2e 100644 --- a/packages/melonjs/src/video/webgl/utils/maxtextures.js +++ b/packages/melonjs/src/video/webgl/utils/maxtextures.js @@ -10,6 +10,7 @@ * ladders. 32 covers current desktop and mobile hardware while staying a * conservative default; raise or lower it with the `maxTextures` setting. * @ignore + * @internal */ export const AUTO_MAX_TEXTURES = 32; @@ -18,6 +19,7 @@ export const AUTO_MAX_TEXTURES = 32; * and a normal-map slot simultaneously, so anything narrower makes the two ids * collide and the sprite samples its own albedo as a normal map. * @ignore + * @internal */ export const MIN_MAX_TEXTURES = 2; @@ -34,6 +36,7 @@ export const MIN_MAX_TEXTURES = 2; * @param {"auto"|number} [setting="auto"] - the `maxTextures` application setting * @returns {number} the pool size, at least 1 and never above `deviceMax` * @ignore + * @internal */ export function resolveMaxTextures(deviceMax, setting = "auto") { // a device that reports nothing usable still has to render something diff --git a/packages/melonjs/src/video/webgl/utils/precision.js b/packages/melonjs/src/video/webgl/utils/precision.js index c106e2dd8a..f69c318892 100644 --- a/packages/melonjs/src/video/webgl/utils/precision.js +++ b/packages/melonjs/src/video/webgl/utils/precision.js @@ -2,6 +2,7 @@ * set precision for the given shader source * won't do anything if the precision is already specified * @ignore + * @internal */ export function setPrecision(src, precision) { // Skip injection when the shader already declares precision near the @@ -39,6 +40,7 @@ export function setPrecision(src, precision) { /** * return the best shader precision for this device, up to the requested cap. * @ignore + * @internal * @param {WebGLRenderingContext} gl - the current WebGL context * @param {boolean} [highPrecision=true] - if false, cap at "mediump" even when "highp" is available * @returns {string} "lowp", "mediump", or "highp" diff --git a/packages/melonjs/src/video/webgl/utils/program.js b/packages/melonjs/src/video/webgl/utils/program.js index 1dc7860353..3ff5b716ce 100644 --- a/packages/melonjs/src/video/webgl/utils/program.js +++ b/packages/melonjs/src/video/webgl/utils/program.js @@ -1,5 +1,6 @@ /** * @ignore + * @internal */ function compileShader(gl, type, source) { const shader = gl.createShader(type); @@ -16,6 +17,7 @@ function compileShader(gl, type, source) { /** * Compile GLSL into a shader object * @ignore + * @internal */ export function compileProgram(gl, vertex, fragment, attributes) { const vertShader = compileShader(gl, gl.VERTEX_SHADER, vertex); diff --git a/packages/melonjs/src/video/webgl/utils/samplercache.js b/packages/melonjs/src/video/webgl/utils/samplercache.js index 817f944a17..3bbc90b2da 100644 --- a/packages/melonjs/src/video/webgl/utils/samplercache.js +++ b/packages/melonjs/src/video/webgl/utils/samplercache.js @@ -16,11 +16,13 @@ * Deliberately mirrors `WebGPUTextureStore.getSampler(filter, repeat, mipmaps)` * — same key, same dedup, so the two backends stay legible side by side. * @ignore + * @internal */ export class GLSamplerCache { /** * @param {WebGL2RenderingContext} gl - the owning context * @ignore + * @internal */ constructor(gl) { this.gl = gl; @@ -51,6 +53,7 @@ export class GLSamplerCache { * @param {boolean} [mipmap=false] - sample the mip chain (trilinear) * @returns {WebGLSampler} the shared sampler * @ignore + * @internal */ get(filter, repeat = "no-repeat", mipmap = false) { if ( @@ -98,6 +101,7 @@ export class GLSamplerCache { * @param {WebGLSampler|null} sampler - the sampler, or `null` to fall back * to the texture's own state * @ignore + * @internal */ bind(unit, sampler) { if (this.bound[unit] === sampler) { @@ -114,6 +118,7 @@ export class GLSamplerCache { * @param {boolean} [destroy=false] - whether to `deleteSampler` first * (orderly teardown; skip it for a lost context) * @ignore + * @internal */ releaseAll(destroy = false) { if (destroy === true) { diff --git a/packages/melonjs/src/video/webgl/utils/string.js b/packages/melonjs/src/video/webgl/utils/string.js index 2671a0eec7..ce1291fa58 100644 --- a/packages/melonjs/src/video/webgl/utils/string.js +++ b/packages/melonjs/src/video/webgl/utils/string.js @@ -1,6 +1,7 @@ /** * clean the given source from space, comments, etc... * @ignore + * @internal */ export function minify(src) { // remove comments @@ -29,6 +30,7 @@ export function minify(src) { * @param {string} defines - `#define` lines, each newline-terminated * @returns {string} the source with the defines injected * @ignore + * @internal */ export function injectDefines(source, defines) { if (!defines) { diff --git a/packages/melonjs/src/video/webgl/utils/topology.js b/packages/melonjs/src/video/webgl/utils/topology.js index 57e2ecb1a3..0e74fa9ff7 100644 --- a/packages/melonjs/src/video/webgl/utils/topology.js +++ b/packages/melonjs/src/video/webgl/utils/topology.js @@ -4,12 +4,14 @@ import { isTopology } from "../../gpu/topology.ts"; * Translate between the backend-neutral topology vocabulary and WebGL's * primitive-mode enums. * @ignore + * @internal */ /** * GL enum name for each topology. Indirection through the name keeps this * table context-free; the value is read off `gl` at call time. * @ignore + * @internal */ const TOPOLOGY_TO_GL_NAME = { "point-list": "POINTS", @@ -25,6 +27,7 @@ const TOPOLOGY_TO_GL_NAME = { * Reverse lookup, built once per context. * @type {WeakMap>} * @ignore + * @internal */ const reverseCache = new WeakMap(); @@ -41,6 +44,7 @@ const reverseCache = new WeakMap(); * @returns {GLenum} the GL primitive mode * @throws {Error} when `value` is neither a known topology nor a number * @ignore + * @internal */ export function resolveTopology(gl, value) { if (typeof value === "number") { @@ -72,6 +76,7 @@ export function resolveTopology(gl, value) { * @param {GLenum} mode - a GL primitive mode * @returns {string|undefined} the topology name, or `undefined` for an unknown mode * @ignore + * @internal */ export function topologyFromGL(gl, mode) { let reverse = reverseCache.get(gl); diff --git a/packages/melonjs/src/video/webgl/utils/uniforms.js b/packages/melonjs/src/video/webgl/utils/uniforms.js index 10b7c56704..f6e3b78833 100644 --- a/packages/melonjs/src/video/webgl/utils/uniforms.js +++ b/packages/melonjs/src/video/webgl/utils/uniforms.js @@ -1,6 +1,7 @@ /** * Hash map of GLSL data types to WebGL Uniform methods * @ignore + * @internal */ const fnHash = { bool: "1i", @@ -36,6 +37,7 @@ const fnHash = { * element-wise (callers commonly reuse a scratch `Float32Array`, so * reference equality would miss every change). * @ignore + * @internal */ function valuesMatch(cached, val) { if (cached === undefined) { @@ -65,6 +67,7 @@ function valuesMatch(cached, val) { * when the length matches — only a length change or a first capture * allocates a fresh array. * @ignore + * @internal */ export function captureValue(prev, val) { if ( @@ -103,6 +106,7 @@ export function captureValue(prev, val) { * and gets its own closure-captured `cache` map, so caches don't leak * across programs. * @ignore + * @internal */ export function extractUniforms(gl, shader) { const uniforms = {}; diff --git a/packages/melonjs/src/video/webgl/utils/vertexformat.js b/packages/melonjs/src/video/webgl/utils/vertexformat.js index b295d4783b..41f8e9c31d 100644 --- a/packages/melonjs/src/video/webgl/utils/vertexformat.js +++ b/packages/melonjs/src/video/webgl/utils/vertexformat.js @@ -8,6 +8,7 @@ import { isVertexFormat, resolveVertexFormat } from "../../gpu/vertexformat.ts"; * rather than from hard-coded constants — which keeps the neutral tier free * of GL references and matches how the rest of the WebGL layer is written. * @ignore + * @internal */ /** @@ -15,6 +16,7 @@ import { isVertexFormat, resolveVertexFormat } from "../../gpu/vertexformat.ts"; * name (rather than the value) is what lets this table exist without a * context: the value is looked up on `gl` at call time. * @ignore + * @internal */ const SCALAR_TO_GL_NAME = { float32: "FLOAT", @@ -37,6 +39,7 @@ const SCALAR_TO_GL_NAME = { * @returns {GLenum} the matching component type * @throws {Error} when `format` is not a supported format name * @ignore + * @internal */ export function glTypeForFormat(gl, format) { const { scalar } = resolveVertexFormat(format); @@ -58,6 +61,7 @@ export function glTypeForFormat(gl, format) { * @param {boolean} normalized - whether integers are scaled into `[0, 1]` / `[-1, 1]` * @returns {string|undefined} the format name, or `undefined` when none exists * @ignore + * @internal */ export function formatFromGL(gl, size, type, normalized) { // `FLOAT` has no normalized spelling: WebGL accepts `normalized: true` diff --git a/packages/melonjs/src/video/webgl/webgl_renderer.js b/packages/melonjs/src/video/webgl/webgl_renderer.js index 5a7ba5c0ca..9947e83383 100644 --- a/packages/melonjs/src/video/webgl/webgl_renderer.js +++ b/packages/melonjs/src/video/webgl/webgl_renderer.js @@ -70,15 +70,20 @@ const _savedProjection = new Matrix3d(); * lazily from a live context on the first `setBlendMode`, because the enum * values are properties of the context object rather than module constants. * @ignore + * @internal */ let GL_BLEND_OP; -/** @ignore */ +/** + * @ignore + * @internal + */ let GL_BLEND_FACTOR; /** * Build the neutral-token → `gl.*` enum lookups for this context. * @param {WebGL2RenderingContext} gl - a live context * @ignore + * @internal */ function initBlendEnums(gl) { GL_BLEND_OP = { @@ -132,7 +137,6 @@ export default class WebGLRenderer extends Renderer { /** * The WebGL context - * @name gl * @type {WebGLRenderingContext} */ this.gl = this.renderTarget.context; @@ -141,6 +145,7 @@ export default class WebGLRenderer extends Renderer { * cached FBO for post-effect processing (lazily created on first use) * @type {WebGLRenderTarget|null} * @ignore + * @internal */ // initialize the render target pool with a WebGL factory // capture targets rasterize the scene — under antiAlias they get a @@ -151,6 +156,10 @@ export default class WebGLRenderer extends Renderer { this.settings.antiAlias === true ? Math.min(4, this.gl.getParameter(this.gl.MAX_SAMPLES)) : 0; + /** + * @ignore + * @internal + */ this._renderTargetPool = new RenderTargetPool((w, h, isCapture) => { return new WebGLRenderTarget(this.gl, w, h, { samples: isCapture === true ? msaaSamples : 0, @@ -161,11 +170,20 @@ export default class WebGLRenderer extends Renderer { * Saved projection matrix for begin/endPostEffect. * @type {Matrix3d} * @ignore + * @internal */ // projections saved by beginPostEffect, one per (possibly nested) // active pass — preallocated slots + a depth counter (zero-alloc // steady state), matching RenderTargetPool's base stack + /** + * @ignore + * @internal + */ this._effectProjectionStack = []; + /** + * @ignore + * @internal + */ this._effectPassDepth = 0; /** @@ -180,21 +198,43 @@ export default class WebGLRenderer extends Renderer { * `toFrameTexture` does too), so a boolean would be cleared by the * inner scope while the outer one is still running. * @ignore + * @internal */ this._advancedBlendEffect = undefined; - /** @ignore */ + /** + * @ignore + * @internal + */ this._advancedBlendCapture = undefined; - /** @ignore */ + /** + * @ignore + * @internal + */ this._advancedBlendTarget = undefined; - /** @ignore */ + /** + * @ignore + * @internal + */ this._advancedBlendOpen = false; - /** @ignore */ + /** + * @ignore + * @internal + */ this._advancedBlendBusy = 0; - /** @ignore */ + /** + * @ignore + * @internal + */ this._advancedBlendParent = null; - /** @ignore */ + /** + * @ignore + * @internal + */ this._advancedBlendStencil = false; - /** @ignore */ + /** + * @ignore + * @internal + */ this._advancedBlendWarned = new Set(); /** @@ -225,6 +265,7 @@ export default class WebGLRenderer extends Renderer { * keyed by source alone. Renderer-owned so every batcher shares it. * @type {GLSamplerCache} * @ignore + * @internal */ this.samplerCache = new GLSamplerCache(this.gl); @@ -241,6 +282,7 @@ export default class WebGLRenderer extends Renderer { * orphaning every handle it tracked and leaking them on the next loss. * @type {TextureStore} * @ignore + * @internal */ this.textureStore = new WebGLTextureStore(this.gl); @@ -261,6 +303,7 @@ export default class WebGLRenderer extends Renderer { * the same reason texture units go through `TextureCache.reserveUnit`. * @type {number} * @ignore + * @internal */ this._nextUniformBindingPoint = 0; @@ -268,6 +311,7 @@ export default class WebGLRenderer extends Renderer { * the default shader precision based on application settings * @type {string} * @ignore + * @internal */ this.shaderPrecision = getMaxShaderPrecision( this.gl, @@ -277,6 +321,7 @@ export default class WebGLRenderer extends Renderer { /** * reusable scratch array for fillRect (2 triangles = 6 vertices) * @ignore + * @internal */ this._rectTriangles = Array.from({ length: 6 }, () => { return { x: 0, y: 0 }; @@ -284,18 +329,34 @@ export default class WebGLRenderer extends Renderer { // scratch AABB reused by `clipRect` for screen-space corner // transforms, kept on the instance so the call doesn't allocate. + /** + * @ignore + * @internal + */ this._clipAABB = new Bounds(); // scratch array for fillPolygon to avoid mutating polygon points + /** + * @ignore + * @internal + */ this._polyVerts = []; // current gradient state (null when using solid color) + /** + * @ignore + * @internal + */ this._currentGradient = null; // the stencil value of currently-VISIBLE pixels under the innermost // active mask, as installed by setMask (0 for an inverted mask, // maskLevel otherwise) — the single source #gradientMask gates and // restores against + /** + * @ignore + * @internal + */ this._maskVisibleRef = 0; /** @@ -323,6 +384,7 @@ export default class WebGLRenderer extends Renderer { * forces the next bind to re-issue `gl.activeTexture`. * @type {number} * @ignore + * @internal */ this._activeTextureUnit = -1; @@ -354,6 +416,10 @@ export default class WebGLRenderer extends Renderer { this.gl.depthMask(false); this.gl.disable(this.gl.SCISSOR_TEST); + /** + * @ignore + * @internal + */ this._scissorActive = false; this.gl.enable(this.gl.BLEND); @@ -519,6 +585,10 @@ export default class WebGLRenderer extends Renderer { // WebGL context not available return super.getSupportedCompressedTextureFormats(); } + /** + * @ignore + * @internal + */ this._compressedTextureFormats = { astc: gl.getExtension("WEBGL_compressed_texture_astc") || @@ -702,6 +772,10 @@ export default class WebGLRenderer extends Renderer { // Lazy re-init happens on the next drawLight call. if (this._lightShader !== undefined) { this._lightShader.destroy?.(); + /** + * @ignore + * @internal + */ this._lightShader = undefined; } if (this._lightAtlas !== undefined) { @@ -714,6 +788,10 @@ export default class WebGLRenderer extends Renderer { this._lightAtlas.sources.forEach((source) => { this.cache.delete?.(source); }); + /** + * @ignore + * @internal + */ this._lightAtlas = undefined; } @@ -722,6 +800,10 @@ export default class WebGLRenderer extends Renderer { // on a still-valid context too (a resize/reset just re-creates it). if (typeof this._frameTexture !== "undefined") { this._frameTexture.destroy(); + /** + * @ignore + * @internal + */ this._frameTexture = undefined; } @@ -733,6 +815,10 @@ export default class WebGLRenderer extends Renderer { // program survives across level transitions instead of leaking a // `WebGLProgram` per reset and re-paying the compile cost. if (this.isContextValid === false) { + /** + * @ignore + * @internal + */ this._orthogonalTMXGPURenderer = undefined; } } @@ -762,6 +848,7 @@ export default class WebGLRenderer extends Renderer { * @param {string} orientation * @returns {object|undefined} * @ignore + * @internal */ _getTMXGPURendererFor(orientation) { if (orientation === "orthogonal") { @@ -975,6 +1062,10 @@ export default class WebGLRenderer extends Renderer { // scratch is allocated lazily on first call so non-lit scenes // don't pay for it if (this._lightUniformsScratch === undefined) { + /** + * @ignore + * @internal + */ this._lightUniformsScratch = createLightUniformScratch(); } const u = packLights( @@ -1012,6 +1103,7 @@ export default class WebGLRenderer extends Renderer { * @returns {number} the claimed binding point * @throws {Error} when the device's binding points are exhausted * @ignore + * @internal */ reserveUniformBindingPoint() { const max = this.gl.getParameter(this.gl.MAX_UNIFORM_BUFFER_BINDINGS); @@ -1076,6 +1168,7 @@ export default class WebGLRenderer extends Renderer { * (no flush on light switch). * @returns {TextureAtlas} * @ignore + * @internal */ _getLightAtlas() { if (this._lightAtlas === undefined) { @@ -1169,7 +1262,10 @@ export default class WebGLRenderer extends Renderer { } } - /** @ignore */ + /** + * @ignore + * @internal + */ _toFrameTexture(options = {}) { const gl = this.gl; const canvas = this.getCanvas(); @@ -1323,6 +1419,7 @@ export default class WebGLRenderer extends Renderer { * wires `: screen_texture` annotated samplers to this object. * @returns {FrameTexture} the shared capture slot * @ignore + * @internal */ getSharedFrameTexture() { if (typeof this._frameTexture === "undefined") { @@ -1346,6 +1443,7 @@ export default class WebGLRenderer extends Renderer { * @param {WebGLBatcher} [except] - a batcher to skip (the one that just bound the * texture — its own cache is already accurate) * @ignore + * @internal */ invalidateTextureUnit(unit, except) { for (const b of this.batchers.values()) { @@ -1360,6 +1458,7 @@ export default class WebGLRenderer extends Renderer { * @param {Renderable} renderable - the renderable requesting post-effect processing * @returns {boolean} true if FBO capture started, false if skipped * @ignore + * @internal */ beginPostEffect(renderable) { // filter to only enabled effects @@ -1420,7 +1519,10 @@ export default class WebGLRenderer extends Renderer { return true; } - /** @ignore */ + /** + * @ignore + * @internal + */ endPostEffect(renderable) { // filter to only enabled effects const effects = renderable.postEffects.filter((fx) => { @@ -1549,6 +1651,7 @@ export default class WebGLRenderer extends Renderer { * loud. * @param {string} what - the excluded path, named for the message * @ignore + * @internal */ _warnAdvancedBlendFallback(what) { const key = `${what}:${this.currentBlendMode}`; @@ -1566,6 +1669,7 @@ export default class WebGLRenderer extends Renderer { * already inside the bracket machinery. The safe form to call from any * path that is about to disturb the destination. * @ignore + * @internal */ _drainAdvancedBlend() { if (this._advancedBlendOpen === true && this._advancedBlendBusy === 0) { @@ -1580,6 +1684,7 @@ export default class WebGLRenderer extends Renderer { * @returns {boolean} false when the effect could not be realized, in which * case the draw proceeds unbracketed (plain source-over) * @ignore + * @internal */ _openAdvancedBlend() { const gl = this.gl; @@ -1656,6 +1761,7 @@ export default class WebGLRenderer extends Renderer { * Close an advanced-blend bracket: drain the offscreen, return to the * parent target, and composite through {@link BlendEffect}. * @ignore + * @internal */ _closeAdvancedBlend() { const gl = this.gl; @@ -2101,6 +2207,7 @@ export default class WebGLRenderer extends Renderer { * @param {Matrix3d} shadowMatrix - the group matrix flattened onto the ground * @param {object} quad - the shared shadow quad * @ignore + * @internal */ /** * Install a blend function for one draw WITHOUT touching @@ -2231,6 +2338,10 @@ export default class WebGLRenderer extends Renderer { this.customShader.isWebGL !== true && this._meshShaderWarned !== true ) { + /** + * @ignore + * @internal + */ this._meshShaderWarned = true; console.warn( "melonJS: this custom shader cannot be hosted on a Mesh by the WebGL renderer (no compiled GLSL program) — the mesh draws with the built-in shading", @@ -2379,7 +2490,7 @@ export default class WebGLRenderer extends Renderer { * @param {number} y - The y axis of the coordinate for the rectangle starting point. * @param {number} width - The rectangle's width. * @param {number} height - The rectangle's height. - * @param {number} radius - The corner radius. + * @param {number} radii - The corner radius. */ roundRect(x, y, width, height, radii) { this.path2D.roundRect(x, y, width, height, radii); @@ -2666,6 +2777,7 @@ export default class WebGLRenderer extends Renderer { * future WebGPU backend reuses it and maps to `GPUFilterMode` instead. * @returns {number} `gl.LINEAR` or `gl.NEAREST` * @ignore + * @internal */ _glTextureFilter() { return this.getDefaultTextureFilter() === "linear" @@ -2679,6 +2791,7 @@ export default class WebGLRenderer extends Renderer { * {@link WebGLRenderer#setAntiAlias} and {@link WebGLRenderer#setTextureFilter}. * @param {number} filter - `gl.LINEAR` or `gl.NEAREST` * @ignore + * @internal */ _reapplyTextureFilter(filter) { const gl = this.gl; @@ -3253,6 +3366,7 @@ export default class WebGLRenderer extends Renderer { * @param {number} w - bounding rect width * @param {number} h - bounding rect height * @ignore + * @internal */ #gradientMask(drawShape, x, y, w, h) { const gl = this.gl; @@ -3524,6 +3638,10 @@ export default class WebGLRenderer extends Renderer { // stencil couldn't represent deeper nesting anyway this.maskLevel = 0x7f; if (this._maskDepthWarned !== true) { + /** + * @ignore + * @internal + */ this._maskDepthWarned = true; console.warn( "melonJS: setMask nesting deeper than 127 — mask level clamped", diff --git a/packages/melonjs/src/video/webgpu/batchers/lit_mesh_batcher.js b/packages/melonjs/src/video/webgpu/batchers/lit_mesh_batcher.js index eb550532fd..06e9911862 100644 --- a/packages/melonjs/src/video/webgpu/batchers/lit_mesh_batcher.js +++ b/packages/melonjs/src/video/webgpu/batchers/lit_mesh_batcher.js @@ -63,6 +63,7 @@ export default class WebGPULitMeshBatcher extends WebGPUMeshBatcher { /** * @override * @ignore + * @internal */ defaultSettings() { const settings = super.defaultSettings(); @@ -73,11 +74,13 @@ export default class WebGPULitMeshBatcher extends WebGPUMeshBatcher { /** * @override * @ignore + * @internal */ /** * the lit tier's instanced variant: its geometry attributes run to * location 3 (the normal), so the instance slots start at 4 * @ignore + * @internal */ instancedVariant() { return LIT_INSTANCED; @@ -87,7 +90,11 @@ export default class WebGPULitMeshBatcher extends WebGPUMeshBatcher { return litMeshWGSL; } - /** add the normal attribute on top of the base layout. @ignore */ + /** + * add the normal attribute on top of the base layout. + * @ignore + * @internal + */ attributeLayout() { const attributes = super.attributeLayout(); attributes.push({ @@ -104,6 +111,7 @@ export default class WebGPULitMeshBatcher extends WebGPUMeshBatcher { * build the light-block layout once per device (init drops it when the * device changes) * @ignore + * @internal */ ensureLightsLayout() { if (typeof this.lightsLayout === "undefined") { @@ -129,6 +137,7 @@ export default class WebGPULitMeshBatcher extends WebGPUMeshBatcher { * the lit family swaps the group-2 filler for the light-block layout * @override * @ignore + * @internal */ bindGroupLayoutList(cache) { return [ @@ -139,7 +148,11 @@ export default class WebGPULitMeshBatcher extends WebGPUMeshBatcher { ]; } - /** push the 12-float lit vertex, appending the world-space normal. @ignore */ + /** + * push the 12-float lit vertex, appending the world-space normal. + * @ignore + * @internal + */ pushVertex(vertexData, x, y, z, u, v, color, mesh, i3) { const n = mesh.normals; vertexData.pushMeshLit( @@ -163,6 +176,7 @@ export default class WebGPULitMeshBatcher extends WebGPUMeshBatcher { * @returns {number} number of floats written * @override * @ignore + * @internal */ buildRetainedVertexData(mesh, out) { return buildLitMeshVertexData(mesh, out, this.vertexSize); @@ -181,6 +195,7 @@ export default class WebGPULitMeshBatcher extends WebGPUMeshBatcher { * ambient. * @override * @ignore + * @internal */ updatePassState() { const renderer = this.renderer; @@ -255,6 +270,7 @@ export default class WebGPULitMeshBatcher extends WebGPUMeshBatcher { * lit draws bind the light block at group 2 * @override * @ignore + * @internal */ bindLights(pass) { // a stale or missing snapshot (a flush outside the drawMesh bracket, diff --git a/packages/melonjs/src/video/webgpu/batchers/lit_quad_batcher.js b/packages/melonjs/src/video/webgpu/batchers/lit_quad_batcher.js index fde2c18154..4f2c3d2069 100644 --- a/packages/melonjs/src/video/webgpu/batchers/lit_quad_batcher.js +++ b/packages/melonjs/src/video/webgpu/batchers/lit_quad_batcher.js @@ -144,6 +144,7 @@ export default class WebGPULitQuadBatcher extends WebGPUQuadBatcher { * @param {HTMLImageElement|HTMLCanvasElement|OffscreenCanvas|ImageBitmap} source - the normal-map image * @returns {object} {texture, view, version, width, height} * @ignore + * @internal */ residentNormalMap(source) { const version = source.version ?? 0; @@ -288,6 +289,7 @@ export default class WebGPULitQuadBatcher extends WebGPUQuadBatcher { * the base segment slots * @override * @ignore + * @internal */ hasPendingMaterial() { return this.currentMaterial !== null; diff --git a/packages/melonjs/src/video/webgpu/batchers/mesh_batcher.js b/packages/melonjs/src/video/webgpu/batchers/mesh_batcher.js index 2c5f6fb26a..2ed353f916 100644 --- a/packages/melonjs/src/video/webgpu/batchers/mesh_batcher.js +++ b/packages/melonjs/src/video/webgpu/batchers/mesh_batcher.js @@ -25,6 +25,7 @@ import WebGPUBatcher from "./webgpu_batcher.js"; * w reserved) (16) + vec4 fogColor (16) + vec4 fogParams (16) * + vec4 fogHeight (16) → 256. * @ignore + * @internal */ export const MESH_UNIFORM_SIZE = 256; @@ -149,6 +150,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { * The instanced variant options for this tier (unlit by default) — where * its instance attributes start and how its vertex stage places them. * @ignore + * @internal */ instancedVariant() { return UNLIT_INSTANCED; @@ -166,6 +168,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { * @param {object} layout - the instance record layout * @returns {string} the family key * @ignore + * @internal */ instancedFamilyFor(layout) { const key = (layout.hasColor ? 1 : 0) | (layout.hasData ? 2 : 0); @@ -207,6 +210,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { * @param {InstancedMesh} mesh - the mesh being drawn * @returns {WebGPUInstanceBuffer} the up-to-date buffer * @ignore + * @internal */ instanceBufferFor(mesh) { let buffer = this.instanced.get(mesh); @@ -236,6 +240,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { * @param {Matrix3d} modelMatrix - where the group sits in the world * @param {number} tint - tint colour in UINT32 (argb) format * @ignore + * @internal */ drawInstancedMesh(mesh, modelMatrix, tint) { const count = mesh.visibleInstanceCount; @@ -328,6 +333,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { * @param {object} layout - the mesh's instance record layout * @returns {string} the pipeline family key * @ignore + * @internal */ instancedShadowFamily(layout) { // Keyed by the record shape, exactly as `instancedFamilyFor` is, and @@ -380,6 +386,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { * @param {number} tint - tint colour in UINT32 (argb) format * @param {object} quad - the shared shadow quad * @ignore + * @internal */ drawInstancedShadow(mesh, shadowMatrix, tint, quad) { const count = mesh.visibleInstanceCount; @@ -443,6 +450,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { * Release the instance buffer held for one mesh, if any. * @param {object} mesh - the mesh whose instance records should be freed * @ignore + * @internal */ releaseInstanced(mesh) { const buffer = this.instanced?.get(mesh); @@ -455,6 +463,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { /** * Release every instance buffer this batcher holds. * @ignore + * @internal */ releaseAllInstanced() { this.instanced?.forEach((buffer) => { @@ -467,6 +476,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { * the first-init settings — the lit subclass overrides the key and * appends its normal attribute * @ignore + * @internal */ defaultSettings() { return { @@ -479,6 +489,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { /** * the WGSL module text of this family * @ignore + * @internal */ shaderSource() { return meshWGSL; @@ -490,6 +501,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { * unorm8x4 — the layout is shared with GL, where float colors dodge * NaN-pattern canonicalization on Metal-backed drivers) = 9 floats. * @ignore + * @internal */ attributeLayout() { return [ @@ -514,6 +526,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { /** * the shape signature keying the group-3 layout in the pipeline cache * @ignore + * @internal */ uniformSignature() { return `mesh:u${MESH_UNIFORM_SIZE}`; @@ -530,6 +543,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { * warn-and-degrade contract. * @returns {string} the pipeline-cache family key * @ignore + * @internal */ activeShaderKey() { const custom = this.customShader; @@ -552,6 +566,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { * the positional bind-group-layout list for this family — the lit * subclass swaps the group-2 filler for its light-block layout * @ignore + * @internal */ bindGroupLayoutList(cache) { return [ @@ -574,6 +589,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { * sampler, one draw range at a time (#1573). The wrap override stays a * property of the mesh, not of the material group. * @ignore + * @internal */ applyMeshMaterial(mesh, texture = mesh.texture) { const renderer = this.renderer; @@ -615,6 +631,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { * @param {number} tint - tint colour in UINT32 (argb) format * @param {object} mesh - the mesh (alphaCutoff / emissive source) * @ignore + * @internal */ setPlacementUniforms(modelMatrix, tint, mesh) { const renderer = this.renderer; @@ -720,6 +737,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { * `x, y, z, u, v, color` — subclasses override to append per-vertex * data matching their attribute layout. * @ignore + * @internal */ pushVertex(vertexData, x, y, z, u, v, color, _mesh, _i3) { vertexData.pushMesh(x, y, z, u, v, color); @@ -763,6 +781,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { * @param {number} from - first index to accumulate * @param {number} length - how many indices to accumulate * @ignore + * @internal */ accumulateRange(mesh, from, length) { const vertices = mesh.vertices; @@ -917,6 +936,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { * bind group 2 — the unlit family interposes the shared empty group; * the lit subclass overrides with its light block * @ignore + * @internal */ bindLights(pass) { pass.setBindGroup(2, this.renderer.pipelineCache.emptyBindGroup); @@ -930,6 +950,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { * @param {Float32Array} out - destination scratch * @returns {number} number of floats written * @ignore + * @internal */ buildRetainedVertexData(mesh, out) { return buildMeshVertexData(mesh, out, this.vertexSize); @@ -941,6 +962,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { * @param {object} mesh - the mesh whose geometry is wanted * @returns {WebGPURetainedGeometry} up-to-date geometry for the mesh * @ignore + * @internal */ retainedGeometryFor(mesh) { let geometry = this.retained.get(mesh); @@ -970,6 +992,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { * @param {Matrix3d} modelMatrix - where the mesh sits in the world * @param {number} tint - tint colour in UINT32 (argb) format * @ignore + * @internal */ drawRetainedMesh(mesh, modelMatrix, tint) { // anything queued must land first, or this draw would reorder @@ -1049,6 +1072,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { * Release the retained geometry held for one mesh, if any. * @param {object} mesh - the mesh whose geometry should be freed * @ignore + * @internal */ releaseRetained(mesh) { this.releaseInstanced(mesh); @@ -1062,6 +1086,7 @@ export default class WebGPUMeshBatcher extends WebGPUBatcher { /** * Release every retained geometry this batcher holds. * @ignore + * @internal */ releaseAllRetained() { this.releaseAllInstanced(); diff --git a/packages/melonjs/src/video/webgpu/batchers/primitive_batcher.js b/packages/melonjs/src/video/webgpu/batchers/primitive_batcher.js index 09e72224fe..0bf4028527 100644 --- a/packages/melonjs/src/video/webgpu/batchers/primitive_batcher.js +++ b/packages/melonjs/src/video/webgpu/batchers/primitive_batcher.js @@ -142,6 +142,7 @@ export default class WebGPUPrimitiveBatcher extends WebGPUBatcher { /** * CPU re-expansion of a triangle fan into a triangle list * @ignore + * @internal */ #drawTriangleFan(verts, vertexCount) { const renderer = this.renderer; @@ -168,6 +169,7 @@ export default class WebGPUPrimitiveBatcher extends WebGPUBatcher { * Push `verts[start..end)` into the vertex buffer, transformed by the * current view matrix. The caller guarantees the range fits. * @ignore + * @internal */ #pushRange(verts, start, end, colorUint32, z) { // the shared neutral range push (z-column-aware transform) — one @@ -188,6 +190,7 @@ export default class WebGPUPrimitiveBatcher extends WebGPUBatcher { * chunks, split on primitive boundaries so every triangle/line stays * whole (same boundary rules as the WebGL batcher). * @ignore + * @internal */ #drawVerticesChunked(topology, verts, vertexCount, colorUint32, z) { // stay one below maxVertex to match isFull()'s `>=` convention @@ -250,6 +253,7 @@ export default class WebGPUPrimitiveBatcher extends WebGPUBatcher { * @param {Point[]} verts - line vertices in pairs [from, to, from, to, ...] * @param {number} vertexCount - number of vertices * @ignore + * @internal */ #expandLinesToTriangles(verts, vertexCount) { // switch to triangle-list topology, then delegate the expansion to diff --git a/packages/melonjs/src/video/webgpu/batchers/quad_batcher.js b/packages/melonjs/src/video/webgpu/batchers/quad_batcher.js index eece2e0ead..c457bc94a5 100644 --- a/packages/melonjs/src/video/webgpu/batchers/quad_batcher.js +++ b/packages/melonjs/src/video/webgpu/batchers/quad_batcher.js @@ -94,13 +94,26 @@ export default class WebGPUQuadBatcher extends WebGPUBatcher { }); /** @type {{view: GPUTextureView, sampler: GPUSampler}[]} indexed by slot */ this.segmentEntries = []; - /** last (view, filter, wrap) resolved to a segment slot @ignore */ + /** + * last (view, filter, wrap) resolved to a segment slot + * @ignore + * @internal + */ this._memoView = null; - /** @ignore */ + /** + * @ignore + * @internal + */ this._memoFilter = null; - /** @ignore */ + /** + * @ignore + * @internal + */ this._memoWrap = null; - /** @ignore */ + /** + * @ignore + * @internal + */ this._memoSlot = 0; // the composed group-1 bind group for the pending segment (lazy) this.segmentGroup = null; @@ -228,6 +241,7 @@ export default class WebGPUQuadBatcher extends WebGPUBatcher { * @param {boolean} reupload - force the source pixels to re-upload * @returns {number} the slot index written to aTextureId * @ignore + * @internal */ segmentSlotFor(texture, reupload) { const renderer = this.renderer; @@ -286,6 +300,7 @@ export default class WebGPUQuadBatcher extends WebGPUBatcher { /** * a stable id for a GPU resource object (bind-group composition keys) * @ignore + * @internal */ resourceId(resource) { let id = this.resourceIds.get(resource); @@ -303,6 +318,7 @@ export default class WebGPUQuadBatcher extends WebGPUBatcher { * resources' identity, so steady-state segments re-use one group. * @returns {GPUBindGroup} the segment's material bind group * @ignore + * @internal */ composeSegmentGroup() { if (this.segmentGroup !== null) { @@ -337,6 +353,7 @@ export default class WebGPUQuadBatcher extends WebGPUBatcher { /** * start the next segment fresh (the pending one was just recorded) * @ignore + * @internal */ resetSegment() { // the table clears each live slot's entry through `onEvict`; truncating @@ -368,6 +385,7 @@ export default class WebGPUQuadBatcher extends WebGPUBatcher { * quad's segment slot (constant across its four corners); the lit and * fast paths pass 0 (single-texture bind groups). * @ignore + * @internal */ pushQuadVertices(x, y, w, h, u0, v0, u1, v1, tint, textureId = 0) { const vertexData = this.vertexData; @@ -403,6 +421,7 @@ export default class WebGPUQuadBatcher extends WebGPUBatcher { * @param {ShaderEffect} [effect] - the effect to composite with * @param {boolean} [keepBlend=false] - keep the current blend mode (else replace) * @ignore + * @internal */ blitTexture(source, x, y, w, h, effect, keepBlend = false) { // drain pending quads under their own material first @@ -518,6 +537,7 @@ export default class WebGPUQuadBatcher extends WebGPUBatcher { * subclass overrides (its material model is the combined color+normal * group, not the segment slots) * @ignore + * @internal */ hasPendingMaterial() { return this.slotTable.size > 0; @@ -529,6 +549,7 @@ export default class WebGPUQuadBatcher extends WebGPUBatcher { * semantic of the fast path vs the pooled blit) * @param {object} binding - the prepared effect binding * @ignore + * @internal */ flushWithEffect(binding) { const renderer = this.renderer; diff --git a/packages/melonjs/src/video/webgpu/buffer/arena.js b/packages/melonjs/src/video/webgpu/buffer/arena.js index a199e99d83..3e81f6cbeb 100644 --- a/packages/melonjs/src/video/webgpu/buffer/arena.js +++ b/packages/melonjs/src/video/webgpu/buffer/arena.js @@ -16,6 +16,7 @@ * mid-frame would invalidate them. Pages persist across frames; `reset()` * just rewinds the bump pointer. * @ignore + * @internal */ export default class WebGPUBufferArena { /** diff --git a/packages/melonjs/src/video/webgpu/buffer/instance_buffer.js b/packages/melonjs/src/video/webgpu/buffer/instance_buffer.js index b6094e682a..eec4802155 100644 --- a/packages/melonjs/src/video/webgpu/buffer/instance_buffer.js +++ b/packages/melonjs/src/video/webgpu/buffer/instance_buffer.js @@ -19,6 +19,7 @@ * `writeBuffer` covering only the dirty span — moving one tree in a forest * of five thousand writes 48 bytes. * @ignore + * @internal */ export default class WebGPUInstanceBuffer { /** @@ -98,6 +99,7 @@ export default class WebGPUInstanceBuffer { * @param {number} byteLength - bytes to copy * @param {Float32Array} data - the CPU-side instance records * @ignore + * @internal */ write(bufferOffset, byteOffset, byteLength, data) { this.renderer.device.queue.writeBuffer( diff --git a/packages/melonjs/src/video/webgpu/buffer/retained_geometry.js b/packages/melonjs/src/video/webgpu/buffer/retained_geometry.js index 3658e7aa88..d95796b0f2 100644 --- a/packages/melonjs/src/video/webgpu/buffer/retained_geometry.js +++ b/packages/melonjs/src/video/webgpu/buffer/retained_geometry.js @@ -19,6 +19,7 @@ let indexPadScratch = new Uint16Array(0); * submit — replaced buffers retire through `renderer.retireBuffer` and * die after the frame's submit. * @ignore + * @internal */ export default class WebGPURetainedGeometry { /** @@ -117,6 +118,7 @@ export default class WebGPURetainedGeometry { * retire both buffers (frame-safe) without resetting the version — the * shared tail of re-allocation and destruction * @ignore + * @internal */ releaseBuffers() { if (this.vertexBuffer !== null) { diff --git a/packages/melonjs/src/video/webgpu/buffer/uniformring.js b/packages/melonjs/src/video/webgpu/buffer/uniformring.js index 2bf3a2e3aa..819509c57f 100644 --- a/packages/melonjs/src/video/webgpu/buffer/uniformring.js +++ b/packages/melonjs/src/video/webgpu/buffer/uniformring.js @@ -16,6 +16,7 @@ import { * were queued. The mid-frame `clearColor` pipeline shares the same pages * through its own layout/bind-group pair. * @ignore + * @internal */ export default class WebGPUUniformRing { /** @@ -47,7 +48,10 @@ export default class WebGPUUniformRing { this.slot = 0; } - /** @ignore */ + /** + * @ignore + * @internal + */ #allocSlot() { const pageIndex = (this.slot / this.slotsPerPage) | 0; if (pageIndex >= this.pages.length) { diff --git a/packages/melonjs/src/video/webgpu/effect_binding.js b/packages/melonjs/src/video/webgpu/effect_binding.js index 90f64ed233..74dacdce06 100644 --- a/packages/melonjs/src/video/webgpu/effect_binding.js +++ b/packages/melonjs/src/video/webgpu/effect_binding.js @@ -12,11 +12,13 @@ * give each bind its own bytes — exactly the vertex arena's rationale, * applied to uniforms. * @ignore + * @internal */ /** * round up to a power-of-two alignment * @ignore + * @internal */ function alignUp(value, alignment) { return (value + alignment - 1) & ~(alignment - 1); @@ -25,6 +27,7 @@ function alignUp(value, alignment) { /** * byte size of the engine MEBuiltins struct (3×vec2f, 16-byte rounded) * @ignore + * @internal */ const ME_SIZE = 32; @@ -35,6 +38,7 @@ const ME_SIZE = 32; * @param {import("./webgpu_renderer.js").default} renderer - the renderer * @param {import("../effects/wgsl_realization.js").default} realization - the effect's WGSL realization * @ignore + * @internal */ function buildEffectGPU(renderer, effect, realization) { const cache = renderer.pipelineCache; @@ -204,6 +208,7 @@ function buildEffectGPU(renderer, effect, realization) { /** * upload a static setTexture source into a resident effect-owned texture * @ignore + * @internal */ function residentTexture(renderer, gpu, name, entry) { let resident = gpu.residentTextures.get(name); @@ -244,6 +249,7 @@ function residentTexture(renderer, gpu, name, entry) { * @returns {{key: string, hasEffectGroup: boolean, bindGroup: GPUBindGroup|null, dynamicOffsets: number[]}|null} * the binding, or null when the effect has no WGSL realization * @ignore + * @internal */ export function prepareEffectBinding(renderer, effect) { const realization = effect.wgslRealization; diff --git a/packages/melonjs/src/video/webgpu/pipeline/bindgroups.js b/packages/melonjs/src/video/webgpu/pipeline/bindgroups.js index c00a4cc7d9..518d4df7be 100644 --- a/packages/melonjs/src/video/webgpu/pipeline/bindgroups.js +++ b/packages/melonjs/src/video/webgpu/pipeline/bindgroups.js @@ -17,6 +17,7 @@ * - group 2 — reserved: lights (the std140 light block ports here). * - group 3 — reserved: per-effect extras (ShaderEffect-WGSL, post FX). * @ignore + * @internal */ export const GROUP_FRAME = 0; export const GROUP_MATERIAL = 1; @@ -27,11 +28,13 @@ export const GROUP_EFFECT = 3; * Byte size of the frame-globals uniform block: * mat4x4 projection (64) + f32 lineWidth (4) + pad to 16 → 80. * @ignore + * @internal */ export const FRAME_UNIFORM_SIZE = 80; /** * Byte size of the clear-color uniform block: vec4 → 16. * @ignore + * @internal */ export const CLEAR_UNIFORM_SIZE = 16; diff --git a/packages/melonjs/src/video/webgpu/pipeline/cache.js b/packages/melonjs/src/video/webgpu/pipeline/cache.js index 72be2bb604..53fdb7a35c 100644 --- a/packages/melonjs/src/video/webgpu/pipeline/cache.js +++ b/packages/melonjs/src/video/webgpu/pipeline/cache.js @@ -19,6 +19,7 @@ import { CLEAR_UNIFORM_SIZE, FRAME_UNIFORM_SIZE } from "./bindgroups.js"; * @returns {GPUBlendState|undefined} the blend state, or `undefined` for * `"none"`, which means replace (no blending) * @ignore + * @internal */ function gpuBlendState(mode, premultipliedAlpha) { const component = blendStateFor(mode, premultipliedAlpha); @@ -34,6 +35,7 @@ function gpuBlendState(mode, premultipliedAlpha) { * comfortably inside WebGPU's base limits (16 sampled textures / 16 * samplers per stage) with headroom for the effect families' samplers. * @ignore + * @internal */ export const MAX_QUAD_TEXTURES = 8; @@ -44,6 +46,7 @@ export const MAX_QUAD_TEXTURES = 8; * must match the pass attachment, and adding it later would invalidate * every cached pipeline. * @ignore + * @internal */ export const DEPTH_STENCIL_FORMAT = "depth24plus-stencil8"; @@ -56,6 +59,7 @@ export const DEPTH_STENCIL_FORMAT = "depth24plus-stencil8"; * - "test" — the masked render phase: fragments pass only where stencil * equals the dynamic `setStencilReference` (GL's `stencilFunc(EQUAL, ref)`) * @ignore + * @internal */ const STENCIL_STATES = { none: { @@ -134,6 +138,7 @@ const STENCIL_STATES = { * the objects every pipeline shares and the uniform ring / texture store * build their bind groups against. * @ignore + * @internal */ export default class WebGPUPipelineCache { /** @@ -306,6 +311,7 @@ export default class WebGPUPipelineCache { /** * monotonic construction counter backing {@link WebGPUPipelineCache#epoch} * @ignore + * @internal */ static epochCounter = 0; diff --git a/packages/melonjs/src/video/webgpu/renderers/tmxlayer/orthogonal.js b/packages/melonjs/src/video/webgpu/renderers/tmxlayer/orthogonal.js index 4ad800e824..1477e61698 100644 --- a/packages/melonjs/src/video/webgpu/renderers/tmxlayer/orthogonal.js +++ b/packages/melonjs/src/video/webgpu/renderers/tmxlayer/orthogonal.js @@ -12,6 +12,7 @@ import tmxLayerWGSL from "../../shaders/tmxlayer.wgsl"; * interleaved with one vec4f at a 16-aligned offset, two f32 and the * trailing vec4f tint → 112 bytes * @ignore + * @internal */ const TMX_UNIFORM_SIZE = 112; @@ -33,6 +34,7 @@ const TMX_UNIFORM_SIZE = 112; * - pipelines flow through the registered `tmxlayer.wgsl` family, keyed * on the frame's blend/stencil state like every other draw * @ignore + * @internal */ export default class OrthogonalTMXLayerGPURenderer { /** @@ -98,6 +100,7 @@ export default class OrthogonalTMXLayerGPURenderer { * Retire every lookup texture and empty the local maps — called from * `WebGPURenderer.reset()` (GAME_RESET) so each level starts clean. * @ignore + * @internal */ reset() { for (const resource of this.resources.values()) { @@ -117,6 +120,7 @@ export default class OrthogonalTMXLayerGPURenderer { * @param {TMXLayer} layer - the layer * @returns {{texture: GPUTexture, view: GPUTextureView, version: number}} * @ignore + * @internal */ getResource(layer) { const device = this.renderer.device; @@ -153,6 +157,7 @@ export default class OrthogonalTMXLayerGPURenderer { * @param {number} tileCount - atlas grid tile count * @returns {object|undefined} the lookup entry * @ignore + * @internal */ getOrUpdateAnimLookup(tileset, tileCount) { if (!tileset.isAnimated || tileset.animations.size === 0) { diff --git a/packages/melonjs/src/video/webgpu/shaders/mesh-instanced.js b/packages/melonjs/src/video/webgpu/shaders/mesh-instanced.js index 5a95407b7b..b483c62728 100644 --- a/packages/melonjs/src/video/webgpu/shaders/mesh-instanced.js +++ b/packages/melonjs/src/video/webgpu/shaders/mesh-instanced.js @@ -37,6 +37,7 @@ import { * @param {string} options.body - the tier's placement body, which reads the `instance` matrix the generated preamble declares and must leave a `clip` value for the shared tail * @returns {string} the instanced module text * @ignore + * @internal */ export function buildInstancedMeshWGSL(source, options) { const { @@ -167,7 +168,11 @@ export function buildInstancedMeshWGSL(source, options) { return module; } -/** the unlit tier's geometry inputs and placement body @ignore */ +/** + * the unlit tier's geometry inputs and placement body + * @ignore + * @internal + */ export const UNLIT_INSTANCED = { baseLocation: 3, // 2 is vFogDepth in the base module now; the instance slot follows it @@ -192,7 +197,11 @@ export const UNLIT_INSTANCED = { ].join("\n"), }; -/** the lit tier's geometry inputs, placement body and normal handling @ignore */ +/** + * the lit tier's geometry inputs, placement body and normal handling + * @ignore + * @internal + */ export const LIT_INSTANCED = { baseLocation: 4, // 4 is vFogDepth in the base module now; the instance slot follows it diff --git a/packages/melonjs/src/video/webgpu/texture/compressed.js b/packages/melonjs/src/video/webgpu/texture/compressed.js index 56ca01d85d..c07a4a5f9d 100644 --- a/packages/melonjs/src/video/webgpu/texture/compressed.js +++ b/packages/melonjs/src/video/webgpu/texture/compressed.js @@ -6,6 +6,7 @@ * "texture-compression-bc", "texture-compression-etc2", * "texture-compression-astc" (PVRTC has no WebGPU equivalent). * @ignore + * @internal */ export const COMPRESSED_FORMATS = new Map([ // S3TC / BC (texture-compression-bc) @@ -54,6 +55,7 @@ export const COMPRESSED_FORMATS = new Map([ * the optional device features the renderer requests when the adapter * offers them * @ignore + * @internal */ export const COMPRESSION_FEATURES = [ "texture-compression-bc", @@ -70,6 +72,7 @@ export const COMPRESSION_FEATURES = [ * @param {object} image - the parsed CompressedImage ({mipmaps, format}) * @param {object} metrics - the COMPRESSED_FORMATS entry for image.format * @ignore + * @internal */ export function uploadCompressedTexture(device, texture, image, metrics) { const mipmaps = image.mipmaps; diff --git a/packages/melonjs/src/video/webgpu/texture/frametexture.js b/packages/melonjs/src/video/webgpu/texture/frametexture.js index 9235066177..c85fe2ed6e 100644 --- a/packages/melonjs/src/video/webgpu/texture/frametexture.js +++ b/packages/melonjs/src/video/webgpu/texture/frametexture.js @@ -13,11 +13,13 @@ import Texture2d from "../../texture/texture2d.ts"; * `setTexture` discriminant contract of the WebGL twin. * @augments Texture2d * @ignore + * @internal */ export class WebGPUFrameTexture extends Texture2d { /** * monotonic generation source shared by every capture instance * @ignore + * @internal */ static generationCounter = 0; diff --git a/packages/melonjs/src/video/webgpu/texture/store.js b/packages/melonjs/src/video/webgpu/texture/store.js index 2bf6625df4..3a9488d837 100644 --- a/packages/melonjs/src/video/webgpu/texture/store.js +++ b/packages/melonjs/src/video/webgpu/texture/store.js @@ -18,6 +18,7 @@ import { COMPRESSED_FORMATS, uploadCompressedTexture } from "./compressed.js"; * rebuilt — the WebGPU analogue of `_reapplyTextureFilter`, without the * re-parameterization). * @ignore + * @internal */ export default class WebGPUTextureStore extends TextureStore { /** @@ -49,6 +50,7 @@ export default class WebGPUTextureStore extends TextureStore { * @param {string} repeat - engine wrap mode string * @returns {GPUSampler} the sampler * @ignore + * @internal */ getSampler(filter, repeat, mipmaps = false) { // same per-axis mapping as MaterialBatcher.createTexture2D @@ -301,6 +303,7 @@ export default class WebGPUTextureStore extends TextureStore { * own command buffer, so the frame's draws sample a complete chain. * @param {object} record - the resident record (mipLevelCount > 1) * @ignore + * @internal */ generateMipmaps(record) { const device = this.device; @@ -380,6 +383,7 @@ export default class WebGPUTextureStore extends TextureStore { * material path and the mesh path, so the two cannot drift on which * view a mip-wanting consumer gets. * @ignore + * @internal */ viewAndSampler(record, texture, wrap, wantMips) { const filter = @@ -417,6 +421,7 @@ export default class WebGPUTextureStore extends TextureStore { * @param {object} [options] - wrap / mipmap options, as `getBinding` takes * @returns {GPUBindGroup} the group-1 bind group * @ignore + * @internal */ getMeshBinding(texture, alphaTexture, options = {}) { // residency first: this is the call that uploads either source, so it @@ -488,6 +493,7 @@ export default class WebGPUTextureStore extends TextureStore { * the per-sampler material bind group for a resident record (shared by * the image and compressed upload paths) * @ignore + * @internal */ bindGroupFor(record, texture, wrap, wantMips = false) { const resolved = this.viewAndSampler(record, texture, wrap, wantMips); @@ -527,6 +533,7 @@ export default class WebGPUTextureStore extends TextureStore { * parks on the renderer's retired list and is destroyed after submit. * @param {GPUTexture} gpuTexture - the texture to dispose of * @ignore + * @internal */ retire(gpuTexture) { this.renderer.retireTexture(gpuTexture); @@ -571,6 +578,7 @@ export default class WebGPUTextureStore extends TextureStore { * defers the actual destroy until the frame that referenced it has retired. * @param {GPUTexture} handle - the texture to release * @ignore + * @internal */ onDestroy(handle) { this.retire(handle); diff --git a/packages/melonjs/src/video/webgpu/webgpu_renderer.js b/packages/melonjs/src/video/webgpu/webgpu_renderer.js index 27158c6b94..9c4ece63df 100644 --- a/packages/melonjs/src/video/webgpu/webgpu_renderer.js +++ b/packages/melonjs/src/video/webgpu/webgpu_renderer.js @@ -118,7 +118,6 @@ export default class WebGPURenderer extends Renderer { /** * The WebGPU device, set once {@link WebGPURenderer#init} resolves. - * @name device * @type {GPUDevice|undefined} * @readonly */ @@ -126,7 +125,6 @@ export default class WebGPURenderer extends Renderer { /** * The WebGPU canvas context - * @name context * @type {GPUCanvasContext} */ this.context = this.renderTarget.context; @@ -262,19 +260,38 @@ export default class WebGPURenderer extends Renderer { * offscreen FBO owns a separate, zeroed stencil) and let the * composite carry the clip instead. Same result, different route. * @ignore + * @internal */ this._advancedBlendEffect = undefined; - /** @ignore */ + /** + * @ignore + * @internal + */ this._advancedBlendCapture = undefined; - /** @ignore */ + /** + * @ignore + * @internal + */ this._advancedBlendTarget = undefined; - /** @ignore */ + /** + * @ignore + * @internal + */ this._advancedBlendOpen = false; - /** @ignore */ + /** + * @ignore + * @internal + */ this._advancedBlendBusy = 0; - /** @ignore */ + /** + * @ignore + * @internal + */ this._advancedBlendParent = null; - /** @ignore */ + /** + * @ignore + * @internal + */ this._advancedBlendWarned = new Set(); // consumed as the next pass's colorLoadOp "clear" (fresh target) @@ -1059,7 +1076,10 @@ export default class WebGPURenderer extends Renderer { } } - /** @ignore */ + /** + * @ignore + * @internal + */ _toFrameTexture(options = {}) { if (typeof this.device === "undefined") { return null; @@ -1210,6 +1230,10 @@ export default class WebGPURenderer extends Renderer { // the pass sample count so MSAA composes with post-effects (the GL // twin resolves via blitFramebuffer). Ping-pong intermediates draw // screen-aligned effect quads only and stay single-sampled. + /** + * @ignore + * @internal + */ this._renderTargetPool ??= new RenderTargetPool((w, h, isCapture) => { return new WebGPURenderTarget(this, w, h, { sampleCount: isCapture === true ? this.canvasSampleCount : 1, @@ -1378,6 +1402,7 @@ export default class WebGPURenderer extends Renderer { * loud. * @param {string} what - the excluded path, named for the message * @ignore + * @internal */ _warnAdvancedBlendFallback(what) { const key = `${what}:${this.currentBlendMode}`; @@ -1394,6 +1419,7 @@ export default class WebGPURenderer extends Renderer { * Close a pending advanced-blend bracket, if one is open and we are not * already inside the bracket machinery. * @ignore + * @internal */ _drainAdvancedBlend() { if (this._advancedBlendOpen === true && this._advancedBlendBusy === 0) { @@ -1407,6 +1433,7 @@ export default class WebGPURenderer extends Renderer { * @returns {boolean} false when the effect could not be realized, in which * case the draw proceeds unbracketed (plain source-over) * @ignore + * @internal */ _openAdvancedBlend() { const canvas = this.getCanvas(); @@ -1459,6 +1486,7 @@ export default class WebGPURenderer extends Renderer { * Close an advanced-blend bracket: drain the offscreen, retarget to the * parent, and composite through {@link BlendEffect}. * @ignore + * @internal */ _closeAdvancedBlend() { const canvas = this.getCanvas(); @@ -1814,6 +1842,7 @@ export default class WebGPURenderer extends Renderer { * @param {Matrix3d} shadowMatrix - the group matrix flattened onto the ground * @param {object} quad - the shared shadow quad * @ignore + * @internal */ drawInstancedShadow(mesh, shadowMatrix, quad) { const tint = this.currentTint.toUint32(this.getGlobalAlpha()); diff --git a/packages/melonjs/typedoc.json b/packages/melonjs/typedoc.json new file mode 100644 index 0000000000..2a0d260a51 --- /dev/null +++ b/packages/melonjs/typedoc.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "entryPoints": ["src/index.ts"], + "tsconfig": "tsconfig.build.json", + "readme": "../../DOC_README.md", + "name": "melonJS", + "hideGenerator": true, + "categorizeByGroup": false, + "navigation": { + "includeCategories": true + }, + "navigationLinks": { + "Website": "https://melonjs.org/", + "Wiki": "https://github.com/melonjs/melonJS/wiki", + "GitHub": "https://github.com/melonjs/melonJS", + "Discord": "https://discord.gg/aur7JMk" + }, + "customJs": "scripts/docs/copy-page.js", + "customCss": "scripts/docs/.docs.css", + "favicon": "../../media/Favicon/Favicon Transparent.png" +}