@ringozz/godot 4.7.2-661 → 4.7.2-676

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -52,8 +52,9 @@ await import('./app.ts'); // may now import @ringozz/godot / react-godot freely
52
52
  | `@ringozz/godot/ClassName` | Classes, one per module — e.g. `@ringozz/godot/Label`, `@ringozz/godot/Node` |
53
53
  | `@ringozz/godot/runtime` | Low-level dispatch: `_C`, `_S`, `_R`, `_G`, `_P`, `_V`, `toValueType`, `getGodot`, `GodotVar` |
54
54
  | `@ringozz/godot/boot` | Platform boot: `getNativeModule()`; web `preloadGodot()` (awaited before importing the app; no-op on desktop) |
55
- | `@ringozz/godot/load` | Async resource loading: `loadResourceAsync`, `loadAsset`, `loadAssetPack` (native `.pck` packs) |
56
- | `@ringozz/godot/pack` | `buildAssetPacks()` + the `godot pack` subcommand: bake a project's `.pck`(s) + loose-texture manifest, one pack per level (its scene, or the `.gltfx` its plan lives in) |
55
+ | `@ringozz/godot/load` | Async resource loading: `loadResourceAsync`, `loadAsset`, `loadAssetPack` (native `.pck` packs), `configurePacks`/`loadPackEntry` (content packs) |
56
+ | `@ringozz/godot/bake` | `buildAssetPacks(opts, run?)` + the `godot pack` subcommand: bake the project's boot `.pck` plus one per declared content pack, with their loose-texture documents. `opts.cwd` picks the project root and `run` replaces the editor, so a test can bake a temp project |
57
+ | `@ringozz/godot/pack` | The pack protocol the bake writes and the plugin/runtime read: `PACK_DOC`/`RELEASE`/`FILES_DIR` and the boot's names, `parseDoc`/`serializeDoc`/`parseRelease`, `packEntries`/`godotEntry`/`entryId`/`pckOf`, and `resolveEntry` (what to mount and stage for one entry) |
57
58
  | `@ringozz/godot/debug` | `initDebug()`, `dumpStr`, `snapshot`, `inspect`, `click`, `find`, `gc` |
58
59
 
59
60
  Class-scoped enums use bare names (import `ProcessMode` from `@ringozz/godot/Node`, not `NodeProcessMode`).
@@ -95,15 +96,37 @@ const tex = await loadResourceAsync('res://textures/icon.jpg', Texture2D); //
95
96
 
96
97
  ### Asset packs
97
98
 
98
- `godot pack` (the `godot` bin, `@ringozz/godot/pack`) bakes a project's assets for the runtime: it imports them, asks `dump-deps.gd` for each source's packed closure and its loose (WebP-backed) textures — including a level's plan, which names refs no resource edge exposes — and exports native `.pck`s — the engine-converted binary resources plus a remap table — through the project's committed `export_presets.cfg`. `loadAssetPack(url)` fetches a pack into MEMFS and hands it to `ProjectSettings.loadResourcePack`; packs are add-only, so several can be mounted and `res://` resolves across all of them.
99
+ `godot pack` (the `godot` bin, `@ringozz/godot/bake`) bakes a project's assets for the runtime: it imports them, asks `dump-deps.gd` for every source's loose (WebP-backed) textures — including a plan, which names refs no resource edge exposes (it warns when a plan resolves no ref at all, or is stamped under another `extras` namespace — that reading has no static check) — and exports one native `.pck` — the engine-converted binary resources plus a remap table — through the project's committed `export_presets.cfg`. `loadAssetPack(url)` fetches a pack into MEMFS and hands it to `ProjectSettings.loadResourcePack`; packs are add-only, so several can be mounted and `res://` resolves across all of them.
99
100
 
100
- The bake always splits: **one pack per level, plus a shared pack**, so a host fetches the shared data and only the level it is playing. A level is its scene — or, in a project that builds levels from their plans at run time, the `.gltfx` its plan lives in; a project with neither under its roots gets a single `shared.pck`. What the runtime reads is `.godot/packs/packs.json` beside the packs: which packs exist, which sources each owns, and which loose sources the host must stage per file (the WebP-backed textures are transcoded). The preload plugin mounts the right packs per asset, so importing a level pulls in the shared pack and that level's, nothing else. How the split is decided — and why it needs no configuration — is in `AGENTS.md`.
101
+ The bake produces **one boot pack** — the project's own sources, exported through its committed `export_presets.cfg` preset, and always mounted by the preload plugin, which is what makes a scene's own run-time paths (a script named by a constant, a level chosen at run time) resolvable — plus **one pack per directory under `dlc/` that declares itself with a `package.json`**: that file gives the pack its name, its dependencies on other packs and its `exports` entries, the pack is that directory and nothing else (the bake rewrites the preset's one `exclude_filter` line per pack), and the bake fails if a pack references anything but the boot sources and its declared dependencies. The boot pack's document is `.godot/packs/packs.json` (`needs` = which loose files each source needs staged, `stage` = the descriptor and product of each loose file the pack owns); a content pack's is a `pack.json` emitted beside its `.pck` (`PACK_DOC` — not `package.json`, which is the pack's own manifest in its source directory, an input the bake reads) (its declared fields plus `needs`/`stage` — the same document the boot's `packs.json` is). Deploying those packs independently — versioning, an index, a CDN — is the host's business, not the bake's.
101
102
 
102
103
  ```ts
103
104
  import { loadAssetPack } from '@ringozz/godot/load';
104
105
  await loadAssetPack('/packs/shared.pck'); // usually the preload plugin does this per asset
105
106
  ```
106
107
 
108
+ ### Content packs
109
+
110
+ A content pack is deployed apart from the app, so nothing about it is in the bundle: the runtime reads a **release** (which version of which pack to mount — a `bun.lock`, or the plain map a local bake emits) and each mounted pack's document, then loads a declared entry. Point the runtime at the packs once, at start-up:
111
+
112
+ ```ts
113
+ import { configurePacks } from '@ringozz/godot/load';
114
+ // The host owns the base: a pack's name, its version and one of its files, addressed its own way.
115
+ configurePacks({
116
+ at: (name, version, file) => `https://cdn.example/packs/${name}@${version}/${file}`,
117
+ release: 'https://cdn.example/packs/release.json', // or the map itself: `{ '@tiv/beach': { version, deps } }`
118
+ });
119
+ ```
120
+
121
+ The boot pack — the app's own sources, which ship beside it — needs no config: the bake renders it into a module (`.godot/packs/boot-pack.js`: its `.pck`, plus a bundled URL per loose product it owns), which every imported asset pulls in, and `configurePacks` merges, so the app's `at` and the boot's config may land in either order. A pack declares its entries (`exports` → the `godot` condition, the `res://` path) and ships **no entry module**: the preload plugin serves one, built from the bake's documents, with one named export per entry. So importing a pack is an ordinary import — and the bake emits the types it resolves to (`package.d.ts`, named by the pack's `types`):
122
+
123
+ ```ts
124
+ import { level } from '@tiv/dlc-beach'; // → a PackedScene, via loadPackEntry(pack, 'level', …)
125
+ ```
126
+
127
+ Mounting is add-only, so every pack in the closure stays mounted for the page's lifetime.
128
+
129
+
107
130
  ### Asset imports
108
131
 
109
132
  Asset imports are resolved by `@ringozz/godot/preload` (a Bun plugin, registered via `bunfig.toml` preload for `bun run`/`bun test` and via `[serve.static] plugins` for `Bun.serve`'s fullstack HTML routes; the module's default export is the single plugin object) into a module per asset. Only **JS imports** are virtualized — HTML asset references (`<link rel="icon">`, `<img src>`) and CSS `url()` refs fall through to Bun's normal (content-hashed) asset handling, so favicons and other web assets co-exist with Godot imports:
@@ -113,7 +136,7 @@ import foo from './models/foo.gltf';
113
136
  const scene = await foo; // PackedScene
114
137
  ```
115
138
 
116
- Each asset module's default export is its load **promise** (`const { materialize, load } = loadAsset(resPath, Class, files, import.meta.hot.data, ready)` — the default is `load`, memoized on the module's HMR data), started eagerly at module import, and it also exports a `materialize` promise (its own files plus its deps' files). The files Godot reads are bundled into the module — `.import` sidecars and native text sources (`tscn`/`tres`/`po`/`gd`/`gdshader`/`gdshaderinc`) are inlined as text, imported products (`.scn`/`.ctex`) are emitted as files — and the module imports its **dependencies as generated modules too**, waiting only for their `materialize` before loading itself (dep loads start at module evaluation and run concurrently). Text-based source assets (`.gltf`/`.tscn`/`.tres`/`.obj`/`.gd`/`.gdshader`/`.gdshaderinc`) are scanned for references (`res://` paths and relative paths ending in known asset extensions); referenced loadable assets become dep modules, native-text leaves are staged as raw text so the engine loads them by `res://` on web, raw `.mtl` files (OBJ materials) are recursed into, and raw `.bin` buffers are import-time only. The modules are virtual (namespace `godot`), and every import of the same asset resolves to the same one (evaluated once) — so the promise is a stable singleton, read with `await` or React 19's `use()`:
139
+ Each asset module's default export is its load **promise** (`const { materialize, load } = loadAsset(resPath, Class, files, import.meta.hot.data, mounting)` — the default is `load`, memoized on the module's HMR data), started eagerly at module import, and it also exports a `materialize` promise (its files staged). The files Godot reads are bundled into the module — `.import` sidecars are inlined as text, imported products (`.ctex`) are emitted as files — from the bake's document, never from scanning the source text: `dump-deps.gd` walked the project at bake time and wrote, per source, the loose (WebP-backed) texture sources the wasm engine cannot decode, and the pack's `stage` gives each of those its sidecar and its product. A packed source resolves inside the mounted `.pck` (the engine-converted resources plus a remap table); only its loose textures are staged per file, transcoded in the browser. The `mounting` promise comes from the bake's boot pack — the module the bake generates beside the packs (`.godot/packs/boot-pack.js`): its `.pck`, plus a bundled URL for every loose product it owns — so importing any asset is also what mounts the app's own pack, and the runtime can stage a content pack's loose files even when the boot owns them. The modules are virtual (namespace `godot`), and every import of the same asset resolves to the same one (evaluated once) — so the promise is a stable singleton, read with `await` or React 19's `use()`:
117
140
 
118
141
  ```tsx
119
142
  import foo from './models/foo.gltf';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ringozz/godot",
3
3
  "author": "Vladimir Davidovich",
4
- "version": "4.7.2-661",
4
+ "version": "4.7.2-676",
5
5
  "description": "Node-API bindings for Godot Engine — call Godot classes from JavaScript",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -27,6 +27,7 @@
27
27
  },
28
28
  "./load": "./src/load.ts",
29
29
  "./pack": "./src/pack.ts",
30
+ "./bake": "./src/bake.ts",
30
31
  "./transcoder": {
31
32
  "browser": "./src/transcoder.browser.ts",
32
33
  "default": "./src/transcoder.ts"
@@ -66,9 +67,9 @@
66
67
  "precision": "single"
67
68
  },
68
69
  "optionalDependencies": {
69
- "@ringozz/godot-macos-arm64": "^4.7.2-661",
70
- "@ringozz/godot-windows-x86_64": "^4.7.2-661",
71
- "@ringozz/godot-web-wasm32": "^4.7.2-661"
70
+ "@ringozz/godot-macos-arm64": "^4.7.2-676",
71
+ "@ringozz/godot-windows-x86_64": "^4.7.2-676",
72
+ "@ringozz/godot-web-wasm32": "^4.7.2-676"
72
73
  },
73
74
  "peerDependencies": {
74
75
  "@types/bun": "*"
package/src/assets.d.ts CHANGED
@@ -30,7 +30,7 @@ declare module '*.gdshaderinc' {
30
30
  export default asset;
31
31
  export const materialize: Promise<unknown>;
32
32
  }
33
-
33
+
34
34
  declare module '*.tres' {
35
35
  import type { Resource } from '@ringozz/godot/Resource';
36
36
  const asset: Promise<Resource>;
@@ -108,6 +108,15 @@ declare module '*.svg' {
108
108
  export const materialize: Promise<unknown>;
109
109
  }
110
110
 
111
+ // The layer manifest `godot/addons/sourcewebp` imports into a `.ctexarray` (a texture array whose
112
+ // layers are source WebP bytes); its product is what is staged.
113
+ declare module '*.webparray' {
114
+ import type { CompressedTexture2DArray } from '@ringozz/godot/CompressedTexture2DArray';
115
+ const asset: Promise<CompressedTexture2DArray>;
116
+ export default asset;
117
+ export const materialize: Promise<unknown>;
118
+ }
119
+
111
120
  declare module '*.exr' {
112
121
  import type { TextureLayered } from '@ringozz/godot/TextureLayered';
113
122
  const asset: Promise<TextureLayered>;