@ringozz/godot 4.7.2-614 → 4.7.2-616
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 +148 -146
- package/package.json +7 -4
- package/src/assets.d.ts +130 -130
- package/src/debug.ts +357 -357
- package/src/editor.ts +107 -0
- package/src/index.ts +54 -50
- package/src/load.ts +231 -231
- package/src/preload.ts +253 -253
- package/src/runtime.ts +107 -107
- package/src/web-image.ts +153 -117
package/README.md
CHANGED
|
@@ -1,146 +1,148 @@
|
|
|
1
|
-
# @ringozz/godot
|
|
2
|
-
|
|
3
|
-
Node-API bindings for the Godot Engine — call Godot classes, value types, and utility functions from JavaScript.
|
|
4
|
-
|
|
5
|
-
This is the core runtime package. The React layer is a separate package ([`@ringozz/react-godot`](../react-godot/README.md)).
|
|
6
|
-
|
|
7
|
-
## Installation
|
|
8
|
-
|
|
9
|
-
```sh
|
|
10
|
-
bun add @ringozz/godot
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
The package ships no engine binary itself — it auto-selects a platform addon from its optional dependencies on install: `@ringozz/godot-macos-arm64`, `@ringozz/godot-windows-x86_64`, or `@ringozz/godot-web-wasm32` (the WASM build is installed everywhere and used on web). No `project.godot` is required — the engine boots from engine defaults with `res://` = your working directory (if a `project.godot` is present at cwd, it is loaded and `res://` still maps to cwd).
|
|
14
|
-
|
|
15
|
-
## Usage
|
|
16
|
-
|
|
17
|
-
On **desktop**, the engine is already running when you import — `getGodot()` returns the instance synchronously. Pump frames with `runGodot()`:
|
|
18
|
-
|
|
19
|
-
```ts
|
|
20
|
-
import { runGodot } from '@ringozz/godot';
|
|
21
|
-
import { Engine } from '@ringozz/godot/Engine';
|
|
22
|
-
import { SceneTree } from '@ringozz/godot/SceneTree';
|
|
23
|
-
|
|
24
|
-
const tree = Engine.getMainLoop() as SceneTree;
|
|
25
|
-
const root = tree.root;
|
|
26
|
-
|
|
27
|
-
const label = new Label();
|
|
28
|
-
label.text = 'hello from godot-node';
|
|
29
|
-
root.addChild(label);
|
|
30
|
-
|
|
31
|
-
const done = runGodot(); // pumps frames until aborted
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### Web
|
|
35
|
-
|
|
36
|
-
The wasm engine boots asynchronously, so on web the entry script must boot it **before** importing the app: `@ringozz/godot/boot`'s `preloadGodot()` starts the engine, and `@ringozz/godot/runtime` then reads the booted module synchronously (the package's `exports` map routes `./boot` to the web leaf in browser-targeted bundles). This keeps the shared module graph top-level-await free, which is also what makes Bun's HMR dev server work. On desktop `preloadGodot()` is a no-op — the engine boots at import.
|
|
37
|
-
|
|
38
|
-
```ts
|
|
39
|
-
// your web entry (referenced by <script type="module"> in the HTML)
|
|
40
|
-
import { preloadGodot } from '@ringozz/godot/boot';
|
|
41
|
-
await preloadGodot();
|
|
42
|
-
await import('./app.ts'); // may now import @ringozz/godot / react-godot freely
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
(That's exactly what `dev/demo.html.ts` does in this repo. A second `<script type="module">` tag can't replace the dynamic import — Bun's fullstack HTML bundler merges all script entries into one chunk, so the browser's in-order script/TLA serialization never applies.)
|
|
46
|
-
|
|
47
|
-
### What's exported where
|
|
48
|
-
|
|
49
|
-
| Specifier | Contents |
|
|
50
|
-
|---|---|
|
|
51
|
-
| `@ringozz/godot` | Value types (`Vector3`, `Color`, …), global enums, heap types, utility functions, global constants, `runGodot()`, RAF polyfills |
|
|
52
|
-
| `@ringozz/godot/ClassName` | Classes, one per module — e.g. `@ringozz/godot/Label`, `@ringozz/godot/Node` |
|
|
53
|
-
| `@ringozz/godot/runtime` | Low-level dispatch: `_C`, `_S`, `_R`, `_G`, `_P`, `_V`, `toValueType`, `getGodot`, `GodotVar` |
|
|
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` |
|
|
56
|
-
| `@ringozz/godot/debug` | `initDebug()`, `dumpStr`, `snapshot`, `inspect`, `click`, `find`, `gc` |
|
|
57
|
-
|
|
58
|
-
Class-scoped enums use bare names (import `ProcessMode` from `@ringozz/godot/Node`, not `NodeProcessMode`).
|
|
59
|
-
|
|
60
|
-
### Value types
|
|
61
|
-
|
|
62
|
-
Godot's built-in value types (`Vector3`, `Color`, `Transform3D`, …) are **named tuples** — labeled array aliases, not classes. Import each type module as a namespace and call its math as functions; constructors are `fromXxx` factories:
|
|
63
|
-
|
|
64
|
-
```ts
|
|
65
|
-
import * as v3 from '@ringozz/godot/Vector3';
|
|
66
|
-
import * as basis from '@ringozz/godot/Basis';
|
|
67
|
-
import type { Vector3 } from '@ringozz/godot/Vector3';
|
|
68
|
-
|
|
69
|
-
const v: Vector3 = [1, 2, 3]; // flat tuple, labels in the type
|
|
70
|
-
const n = v3.normalized(v); // math API per type module
|
|
71
|
-
const b = basis.fromAxisAngle([0, 1, 0], 1.57);
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
- **Shapes**: flat types are scalar-labeled (`Vector3 = [x: number, y: number, z: number]`, `Color = [r, g, b, a?]`); nested types are row-labeled tuples of the flat alias (`Transform3D = [x, y, z, origin]`, `AABB = [position, size]`). **Wrong-arity arrays fail typecheck**; `Color`'s `a` is the only optional element (alpha defaults 1).
|
|
75
|
-
- **Getters/setters/props** all use the same tuple shapes — `node.position = [1, 2, 3]` reads back `[x, y, z]`; JSX props in `@ringozz/react-godot` accept them too.
|
|
76
|
-
- A plain tuple stored in a **Variant-typed slot** (`setMeta`, a direct `tweenProperty` final value) becomes a generic Godot `Array` — a tuple carries no type. Wrap it with `toValueType(node, 'prop', tuple)` from `@ringozz/godot/runtime` to store the typed value.
|
|
77
|
-
|
|
78
|
-
### Async resource loading
|
|
79
|
-
|
|
80
|
-
The engine loads pre-baked native resources (`.scn`, `.ctex`, …) through `ResourceLoader`. On desktop these are real files (`res://` = cwd); on web there is no filesystem, so the asset's bundled files — `.import` sidecars as text and imported products (`.scn`/`.ctex`) as emitted asset paths — are staged into Emscripten's in-memory MEMFS (transient, no IndexedDB, no persistent copy) by the generated asset modules, handing the fetched bytes straight to MEMFS via Godot's own `copyToFS` (`FS.createDataFile` with `canOwn` — zero copy, JS-heap only). On web, `.ctex` files are decoded first: the embedded PNG/WebP blobs go through the browser's `createImageBitmap` and the container is rebuilt as raw RGBA (`DATA_FORMAT_IMAGE`), so no image codec runs in wasm. The source file itself is never fetched.
|
|
81
|
-
|
|
82
|
-
```ts
|
|
83
|
-
import { loadResourceAsync } from '@ringozz/godot/load';
|
|
84
|
-
import { PackedScene } from '@ringozz/godot/PackedScene';
|
|
85
|
-
import { Texture2D } from '@ringozz/godot/Texture2D';
|
|
86
|
-
|
|
87
|
-
const scene = await loadResourceAsync('res://models/foo.gltf', PackedScene); // PackedScene
|
|
88
|
-
const node = scene.instantiate();
|
|
89
|
-
const tex = await loadResourceAsync('res://textures/icon.jpg', Texture2D); // Texture2D
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
- `loadResourceAsync(path, cls, files?)` — generic over the Godot class: `cls.name` is the `ResourceLoader` type hint, and the return type is `InstanceType<typeof cls>`. Loads in the background (`loadThreadedRequest` + status polling). Godot default arguments apply: the napi dispatch truncates trailing `undefined` args, so `loadThreadedRequest` uses its default `CACHE_MODE_REUSE` and the resource stays cached in the engine (scene re-references don't re-read the file). On web it only works for paths already staged into MEMFS (generated asset modules handle this). When the asset's `files` map is passed, the staged product files (`.ctex`/`.scn`/native sources) are deleted from MEMFS after the resource loads — only the `.import` sidecars are kept, since they route imported source paths to their products. The decoded texture bytes don't linger in the JS heap.
|
|
93
|
-
- `loadAsset(path, cls, files, deps, data)` — the generated asset modules' entry point (also usable directly): returns `{ materialize, load }`. It checks the engine's `ResourceCache` first (when the asset is already loaded, `load` resolves to the cached instance and staging is skipped), stages the bundled files via Godot's `copyToFS` (zero-copy handover of the fetched bytes; a no-op on desktop where the files already exist), loads via `loadResourceAsync`, and memoizes `load` on `data` (pass `import.meta.hot.data`) so HMR re-evaluations reuse the same fulfilled promise.
|
|
94
|
-
|
|
95
|
-
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:
|
|
96
|
-
|
|
97
|
-
```ts
|
|
98
|
-
import foo from './models/foo.gltf';
|
|
99
|
-
const scene = await foo; // PackedScene
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
Each asset module's default export is its load **promise** (`const { materialize, load } = loadAsset(resPath, Class, files, deps, import.meta.hot.data)` — 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`) 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`) 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()`:
|
|
103
|
-
|
|
104
|
-
```tsx
|
|
105
|
-
import foo from './models/foo.gltf';
|
|
106
|
-
import { Suspense, use } from 'react';
|
|
107
|
-
|
|
108
|
-
function Foo() {
|
|
109
|
-
const scene = use(foo); // suspends until the scene loads
|
|
110
|
-
return <FooView scene={scene} />;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
<Suspense fallback={<Label text="Loading…" />}>
|
|
114
|
-
<Foo />
|
|
115
|
-
</Suspense>
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
Each extension maps to its Godot class (source assets only — `gltf`/`tscn`/`obj` → `PackedScene`, `gd` → `GDScript`, `jpg`/`jpeg`/`png`/`webp`/`svg` → `CompressedTexture2D`, `exr`/`hdr` → `TextureLayered`, `wav` → `AudioStreamWAV`, `ogg` → `AudioStreamOggVorbis`, `mp3` → `AudioStreamMP3`, `ttf`/`otf` → `FontFile`, `tres` → `Resource`, `po` → `Translation`), declared in `src/assets.d.ts`. Imported products (`.scn`/`.ctex`) are never imported directly. `.gd` scripts import as `Promise<GDScript>`, so `import script from './x.gd'; const gd = await script;` works like any other resource — and when a `.tscn` references the same `.gd`, Godot's `ResourceLoader` cache returns the same instance (parsed once).
|
|
119
|
-
|
|
120
|
-
Textures are shared only through Godot's `ResourceLoader` path cache. The glTF import pipeline may produce per-scene texture instances (same `res://` path, separate objects), so don't assume two scenes referencing the same image share one texture object.
|
|
121
|
-
|
|
122
|
-
### Debugging
|
|
123
|
-
|
|
124
|
-
```ts
|
|
125
|
-
import { initDebug } from '@ringozz/godot/debug';
|
|
126
|
-
initDebug();
|
|
127
|
-
// singletons + helpers now on globalThis.$: $.Engine, $.tree, $.dumpStr(node), $.snapshot([pattern]), $.inspect(path), $.click(path), $.find([pattern], [type]), $.paused, $.gc()
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
- `dumpStr(obj)` renders value types inline (`(1.0, 2.0, 3.0)`, arrays, dictionaries) via Godot's `str()` and dumps objects via Godot's `var_to_str`, with the node's `name` prepended.
|
|
131
|
-
- `snapshot(pattern?, node?)` dumps the scene tree from the root `Window` as `Class "name" (N children)` lines; pass a string (case-insensitive substring) or `RegExp` to filter. `$.snapshot()` with no arg dumps the whole tree.
|
|
132
|
-
- `inspect(path)` resolves a node by absolute NodePath (`/root/Box`) or name/glob pattern (`findChild`) and returns its `dumpStr`.
|
|
133
|
-
- `click(path)` synthesizes a left-click at the center of a `Control` via `Window.pushInput` (device-space coordinates), returning the node's `dumpStr` or `null` if it isn't a `Control`.
|
|
134
|
-
- `find(pattern?, type?)` returns a JS array of nodes matching a name glob and/or class (`$.find('*', 'RigidBody3D')` lists all physics bodies).
|
|
135
|
-
- `$.tree` is the live `SceneTree`; `$.paused = true` freezes the scene tree for inspection; `$.paused = false` resumes.
|
|
136
|
-
|
|
137
|
-
`initDebug` also registers an `uncaughtException` handler that keeps the process alive, polyfills `DOMRect` (not defined in Bun, needed by `getBoundingClientRect()`), and adds `getBoundingClientRect()` to `CanvasItem`/`Node3D` (Node3D covers descendant meshes; returns CSS-pixel coordinates).
|
|
138
|
-
|
|
139
|
-
## Notes
|
|
140
|
-
|
|
141
|
-
- **Memory**: non-RefCounted objects (`Node`, `Node2D`, `Node3D`, …) must call `free()` explicitly. RefCounted objects are managed by Godot's ref counting; calling `free()` clears the JS wrapper (decrements the ref).
|
|
142
|
-
- **Class-registration tree-shaking**: `ClassDB.instantiate('X')` requires the JS class to be value-imported (`import { Label } from '@ringozz/godot/Label'`). If a class is only type-used (e.g. `as Label` casts), bundlers may drop its registration side effect, and wrappers fall back to an ancestor class. Render through JSX is unaffected. Workaround: keep a value reference (`void Label;`).
|
|
143
|
-
|
|
144
|
-
## Development
|
|
145
|
-
|
|
146
|
-
`gen/` is generated (and gitignored) by `dev/codegen.ts` from `godot --dump-extension-api-with-docs`. From the repo root: `bun run prebuild` (codegen + typecheck), `bun run predev` (imports `dev/assets/` via the editor), `bun run build` (native addon), `bun run test`, and `bun run dev` (web dev server). See [`AGENTS.md`](../../AGENTS.md) for the full workflow.
|
|
1
|
+
# @ringozz/godot
|
|
2
|
+
|
|
3
|
+
Node-API bindings for the Godot Engine — call Godot classes, value types, and utility functions from JavaScript.
|
|
4
|
+
|
|
5
|
+
This is the core runtime package. The React layer is a separate package ([`@ringozz/react-godot`](../react-godot/README.md)).
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
bun add @ringozz/godot
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The package ships no engine binary itself — it auto-selects a platform addon from its optional dependencies on install: `@ringozz/godot-macos-arm64`, `@ringozz/godot-windows-x86_64`, or `@ringozz/godot-web-wasm32` (the WASM build is installed everywhere and used on web). No `project.godot` is required — the engine boots from engine defaults with `res://` = your working directory (if a `project.godot` is present at cwd, it is loaded and `res://` still maps to cwd).
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
On **desktop**, the engine is already running when you import — `getGodot()` returns the instance synchronously. Pump frames with `runGodot()`:
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { runGodot } from '@ringozz/godot';
|
|
21
|
+
import { Engine } from '@ringozz/godot/Engine';
|
|
22
|
+
import { SceneTree } from '@ringozz/godot/SceneTree';
|
|
23
|
+
|
|
24
|
+
const tree = Engine.getMainLoop() as SceneTree;
|
|
25
|
+
const root = tree.root;
|
|
26
|
+
|
|
27
|
+
const label = new Label();
|
|
28
|
+
label.text = 'hello from godot-node';
|
|
29
|
+
root.addChild(label);
|
|
30
|
+
|
|
31
|
+
const done = runGodot(); // pumps frames until aborted
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Web
|
|
35
|
+
|
|
36
|
+
The wasm engine boots asynchronously, so on web the entry script must boot it **before** importing the app: `@ringozz/godot/boot`'s `preloadGodot()` starts the engine, and `@ringozz/godot/runtime` then reads the booted module synchronously (the package's `exports` map routes `./boot` to the web leaf in browser-targeted bundles). This keeps the shared module graph top-level-await free, which is also what makes Bun's HMR dev server work. On desktop `preloadGodot()` is a no-op — the engine boots at import.
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
// your web entry (referenced by <script type="module"> in the HTML)
|
|
40
|
+
import { preloadGodot } from '@ringozz/godot/boot';
|
|
41
|
+
await preloadGodot();
|
|
42
|
+
await import('./app.ts'); // may now import @ringozz/godot / react-godot freely
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
(That's exactly what `dev/demo.html.ts` does in this repo. A second `<script type="module">` tag can't replace the dynamic import — Bun's fullstack HTML bundler merges all script entries into one chunk, so the browser's in-order script/TLA serialization never applies.)
|
|
46
|
+
|
|
47
|
+
### What's exported where
|
|
48
|
+
|
|
49
|
+
| Specifier | Contents |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `@ringozz/godot` | Value types (`Vector3`, `Color`, …), global enums, heap types, utility functions, global constants, `runGodot()`, RAF polyfills |
|
|
52
|
+
| `@ringozz/godot/ClassName` | Classes, one per module — e.g. `@ringozz/godot/Label`, `@ringozz/godot/Node` |
|
|
53
|
+
| `@ringozz/godot/runtime` | Low-level dispatch: `_C`, `_S`, `_R`, `_G`, `_P`, `_V`, `toValueType`, `getGodot`, `GodotVar` |
|
|
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` |
|
|
56
|
+
| `@ringozz/godot/debug` | `initDebug()`, `dumpStr`, `snapshot`, `inspect`, `click`, `find`, `gc` |
|
|
57
|
+
|
|
58
|
+
Class-scoped enums use bare names (import `ProcessMode` from `@ringozz/godot/Node`, not `NodeProcessMode`).
|
|
59
|
+
|
|
60
|
+
### Value types
|
|
61
|
+
|
|
62
|
+
Godot's built-in value types (`Vector3`, `Color`, `Transform3D`, …) are **named tuples** — labeled array aliases, not classes. Import each type module as a namespace and call its math as functions; constructors are `fromXxx` factories:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import * as v3 from '@ringozz/godot/Vector3';
|
|
66
|
+
import * as basis from '@ringozz/godot/Basis';
|
|
67
|
+
import type { Vector3 } from '@ringozz/godot/Vector3';
|
|
68
|
+
|
|
69
|
+
const v: Vector3 = [1, 2, 3]; // flat tuple, labels in the type
|
|
70
|
+
const n = v3.normalized(v); // math API per type module
|
|
71
|
+
const b = basis.fromAxisAngle([0, 1, 0], 1.57);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
- **Shapes**: flat types are scalar-labeled (`Vector3 = [x: number, y: number, z: number]`, `Color = [r, g, b, a?]`); nested types are row-labeled tuples of the flat alias (`Transform3D = [x, y, z, origin]`, `AABB = [position, size]`). **Wrong-arity arrays fail typecheck**; `Color`'s `a` is the only optional element (alpha defaults 1).
|
|
75
|
+
- **Getters/setters/props** all use the same tuple shapes — `node.position = [1, 2, 3]` reads back `[x, y, z]`; JSX props in `@ringozz/react-godot` accept them too.
|
|
76
|
+
- A plain tuple stored in a **Variant-typed slot** (`setMeta`, a direct `tweenProperty` final value) becomes a generic Godot `Array` — a tuple carries no type. Wrap it with `toValueType(node, 'prop', tuple)` from `@ringozz/godot/runtime` to store the typed value.
|
|
77
|
+
|
|
78
|
+
### Async resource loading
|
|
79
|
+
|
|
80
|
+
The engine loads pre-baked native resources (`.scn`, `.ctex`, …) through `ResourceLoader`. On desktop these are real files (`res://` = cwd); on web there is no filesystem, so the asset's bundled files — `.import` sidecars as text and imported products (`.scn`/`.ctex`) as emitted asset paths — are staged into Emscripten's in-memory MEMFS (transient, no IndexedDB, no persistent copy) by the generated asset modules, handing the fetched bytes straight to MEMFS via Godot's own `copyToFS` (`FS.createDataFile` with `canOwn` — zero copy, JS-heap only). On web, `.ctex` files are decoded first: the embedded PNG/WebP blobs go through the browser's `createImageBitmap` and the container is rebuilt as raw RGBA (`DATA_FORMAT_IMAGE`), so no image codec runs in wasm. The source file itself is never fetched.
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
import { loadResourceAsync } from '@ringozz/godot/load';
|
|
84
|
+
import { PackedScene } from '@ringozz/godot/PackedScene';
|
|
85
|
+
import { Texture2D } from '@ringozz/godot/Texture2D';
|
|
86
|
+
|
|
87
|
+
const scene = await loadResourceAsync('res://models/foo.gltf', PackedScene); // PackedScene
|
|
88
|
+
const node = scene.instantiate();
|
|
89
|
+
const tex = await loadResourceAsync('res://textures/icon.jpg', Texture2D); // Texture2D
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
- `loadResourceAsync(path, cls, files?)` — generic over the Godot class: `cls.name` is the `ResourceLoader` type hint, and the return type is `InstanceType<typeof cls>`. Loads in the background (`loadThreadedRequest` + status polling). Godot default arguments apply: the napi dispatch truncates trailing `undefined` args, so `loadThreadedRequest` uses its default `CACHE_MODE_REUSE` and the resource stays cached in the engine (scene re-references don't re-read the file). On web it only works for paths already staged into MEMFS (generated asset modules handle this). When the asset's `files` map is passed, the staged product files (`.ctex`/`.scn`/native sources) are deleted from MEMFS after the resource loads — only the `.import` sidecars are kept, since they route imported source paths to their products. The decoded texture bytes don't linger in the JS heap.
|
|
93
|
+
- `loadAsset(path, cls, files, deps, data)` — the generated asset modules' entry point (also usable directly): returns `{ materialize, load }`. It checks the engine's `ResourceCache` first (when the asset is already loaded, `load` resolves to the cached instance and staging is skipped), stages the bundled files via Godot's `copyToFS` (zero-copy handover of the fetched bytes; a no-op on desktop where the files already exist), loads via `loadResourceAsync`, and memoizes `load` on `data` (pass `import.meta.hot.data`) so HMR re-evaluations reuse the same fulfilled promise.
|
|
94
|
+
|
|
95
|
+
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:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import foo from './models/foo.gltf';
|
|
99
|
+
const scene = await foo; // PackedScene
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Each asset module's default export is its load **promise** (`const { materialize, load } = loadAsset(resPath, Class, files, deps, import.meta.hot.data)` — 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`) 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`) 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()`:
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
import foo from './models/foo.gltf';
|
|
106
|
+
import { Suspense, use } from 'react';
|
|
107
|
+
|
|
108
|
+
function Foo() {
|
|
109
|
+
const scene = use(foo); // suspends until the scene loads
|
|
110
|
+
return <FooView scene={scene} />;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
<Suspense fallback={<Label text="Loading…" />}>
|
|
114
|
+
<Foo />
|
|
115
|
+
</Suspense>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Each extension maps to its Godot class (source assets only — `gltf`/`tscn`/`obj` → `PackedScene`, `gd` → `GDScript`, `jpg`/`jpeg`/`png`/`webp`/`svg` → `CompressedTexture2D`, `exr`/`hdr` → `TextureLayered`, `wav` → `AudioStreamWAV`, `ogg` → `AudioStreamOggVorbis`, `mp3` → `AudioStreamMP3`, `ttf`/`otf` → `FontFile`, `tres` → `Resource`, `po` → `Translation`), declared in `src/assets.d.ts`. Imported products (`.scn`/`.ctex`) are never imported directly. `.gd` scripts import as `Promise<GDScript>`, so `import script from './x.gd'; const gd = await script;` works like any other resource — and when a `.tscn` references the same `.gd`, Godot's `ResourceLoader` cache returns the same instance (parsed once).
|
|
119
|
+
|
|
120
|
+
Textures are shared only through Godot's `ResourceLoader` path cache. The glTF import pipeline may produce per-scene texture instances (same `res://` path, separate objects), so don't assume two scenes referencing the same image share one texture object.
|
|
121
|
+
|
|
122
|
+
### Debugging
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import { initDebug } from '@ringozz/godot/debug';
|
|
126
|
+
initDebug();
|
|
127
|
+
// singletons + helpers now on globalThis.$: $.Engine, $.tree, $.dumpStr(node), $.snapshot([pattern]), $.inspect(path), $.click(path), $.find([pattern], [type]), $.paused, $.gc()
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
- `dumpStr(obj)` renders value types inline (`(1.0, 2.0, 3.0)`, arrays, dictionaries) via Godot's `str()` and dumps objects via Godot's `var_to_str`, with the node's `name` prepended.
|
|
131
|
+
- `snapshot(pattern?, node?)` dumps the scene tree from the root `Window` as `Class "name" (N children)` lines; pass a string (case-insensitive substring) or `RegExp` to filter. `$.snapshot()` with no arg dumps the whole tree.
|
|
132
|
+
- `inspect(path)` resolves a node by absolute NodePath (`/root/Box`) or name/glob pattern (`findChild`) and returns its `dumpStr`.
|
|
133
|
+
- `click(path)` synthesizes a left-click at the center of a `Control` via `Window.pushInput` (device-space coordinates), returning the node's `dumpStr` or `null` if it isn't a `Control`.
|
|
134
|
+
- `find(pattern?, type?)` returns a JS array of nodes matching a name glob and/or class (`$.find('*', 'RigidBody3D')` lists all physics bodies).
|
|
135
|
+
- `$.tree` is the live `SceneTree`; `$.paused = true` freezes the scene tree for inspection; `$.paused = false` resumes.
|
|
136
|
+
|
|
137
|
+
`initDebug` also registers an `uncaughtException` handler that keeps the process alive, polyfills `DOMRect` (not defined in Bun, needed by `getBoundingClientRect()`), and adds `getBoundingClientRect()` to `CanvasItem`/`Node3D` (Node3D covers descendant meshes; returns CSS-pixel coordinates).
|
|
138
|
+
|
|
139
|
+
## Notes
|
|
140
|
+
|
|
141
|
+
- **Memory**: non-RefCounted objects (`Node`, `Node2D`, `Node3D`, …) must call `free()` explicitly. RefCounted objects are managed by Godot's ref counting; calling `free()` clears the JS wrapper (decrements the ref).
|
|
142
|
+
- **Class-registration tree-shaking**: `ClassDB.instantiate('X')` requires the JS class to be value-imported (`import { Label } from '@ringozz/godot/Label'`). If a class is only type-used (e.g. `as Label` casts), bundlers may drop its registration side effect, and wrappers fall back to an ancestor class. Render through JSX is unaffected. Workaround: keep a value reference (`void Label;`).
|
|
143
|
+
|
|
144
|
+
## Development
|
|
145
|
+
|
|
146
|
+
`gen/` is generated (and gitignored) by `dev/codegen.ts` from `godot --dump-extension-api-with-docs`. From the repo root: `bun run prebuild` (codegen + typecheck), `bun run predev` (imports `dev/assets/` via the editor), `bun run build` (native addon), `bun run test`, and `bun run dev` (web dev server). See [`AGENTS.md`](../../AGENTS.md) for the full workflow.
|
|
147
|
+
|
|
148
|
+
The package also ships a `godot` bin (`src/editor.ts`) used by the scripts: it resolves `GODOT_PATH` → a system `godot` on `PATH` → `~/.local/bin/godot`, and downloads the pinned official editor from [`godotengine/godot-builds`](https://github.com/godotengine/godot-builds) into `~/.local/bin/godot` when none is found.
|
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-
|
|
4
|
+
"version": "4.7.2-616",
|
|
5
5
|
"description": "Node-API bindings for Godot Engine — call Godot classes from JavaScript",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
"type": "module",
|
|
13
13
|
"main": "./src/index.ts",
|
|
14
14
|
"types": "./gen/index.ts",
|
|
15
|
+
"bin": {
|
|
16
|
+
"godot": "./src/editor.ts"
|
|
17
|
+
},
|
|
15
18
|
"exports": {
|
|
16
19
|
".": "./src/index.ts",
|
|
17
20
|
"./assets": {
|
|
@@ -58,9 +61,9 @@
|
|
|
58
61
|
"precision": "single"
|
|
59
62
|
},
|
|
60
63
|
"optionalDependencies": {
|
|
61
|
-
"@ringozz/godot-macos-arm64": "^4.7.2-
|
|
62
|
-
"@ringozz/godot-windows-x86_64": "^4.7.2-
|
|
63
|
-
"@ringozz/godot-web-wasm32": "^4.7.2-
|
|
64
|
+
"@ringozz/godot-macos-arm64": "^4.7.2-616",
|
|
65
|
+
"@ringozz/godot-windows-x86_64": "^4.7.2-616",
|
|
66
|
+
"@ringozz/godot-web-wasm32": "^4.7.2-616"
|
|
64
67
|
},
|
|
65
68
|
"peerDependencies": {
|
|
66
69
|
"@types/bun": "*"
|
package/src/assets.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
/**********************************************************************
|
|
2
|
-
Copyright (c) Vladimir Davidovich. All rights reserved.
|
|
3
|
-
***********************************************************************/
|
|
4
|
-
|
|
5
|
-
// Ambient types for Godot asset imports, resolved by `@ringozz/godot/preload`
|
|
6
|
-
// into modules that export a `materialize` promise (files staged into MEMFS) and
|
|
7
|
-
// default to the load promise (`const { materialize, load } = loadAsset(path,
|
|
8
|
-
// Class, files, deps, import.meta.hot.data)` — `load` memoized on the module's
|
|
9
|
-
// HMR data, so re-evaluations return the same fulfilled promise). The default is
|
|
10
|
-
// a stable module singleton, so it can be passed to React's `use()` under
|
|
11
|
-
// `<Suspense>`.
|
|
12
|
-
|
|
1
|
+
/**********************************************************************
|
|
2
|
+
Copyright (c) Vladimir Davidovich. All rights reserved.
|
|
3
|
+
***********************************************************************/
|
|
4
|
+
|
|
5
|
+
// Ambient types for Godot asset imports, resolved by `@ringozz/godot/preload`
|
|
6
|
+
// into modules that export a `materialize` promise (files staged into MEMFS) and
|
|
7
|
+
// default to the load promise (`const { materialize, load } = loadAsset(path,
|
|
8
|
+
// Class, files, deps, import.meta.hot.data)` — `load` memoized on the module's
|
|
9
|
+
// HMR data, so re-evaluations return the same fulfilled promise). The default is
|
|
10
|
+
// a stable module singleton, so it can be passed to React's `use()` under
|
|
11
|
+
// `<Suspense>`.
|
|
12
|
+
|
|
13
13
|
declare module '*.gd' {
|
|
14
14
|
import type { GDScript } from '@ringozz/godot/GDScript';
|
|
15
15
|
const asset: Promise<GDScript>;
|
|
@@ -17,121 +17,121 @@ declare module '*.gd' {
|
|
|
17
17
|
export const materialize: Promise<unknown>;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
declare module '*.tres' {
|
|
21
|
-
import type { Resource } from '@ringozz/godot/Resource';
|
|
22
|
-
const asset: Promise<Resource>;
|
|
23
|
-
export default asset;
|
|
24
|
-
export const materialize: Promise<unknown>;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
declare module '*.po' {
|
|
28
|
-
import type { Translation } from '@ringozz/godot/Translation';
|
|
29
|
-
const asset: Promise<Translation>;
|
|
30
|
-
export default asset;
|
|
31
|
-
export const materialize: Promise<unknown>;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
declare module '*.gltf' {
|
|
35
|
-
import type { PackedScene } from '@ringozz/godot/PackedScene';
|
|
36
|
-
const asset: Promise<PackedScene>;
|
|
37
|
-
export default asset;
|
|
38
|
-
export const materialize: Promise<unknown>;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
declare module '*.tscn' {
|
|
42
|
-
import type { PackedScene } from '@ringozz/godot/PackedScene';
|
|
43
|
-
const asset: Promise<PackedScene>;
|
|
44
|
-
export default asset;
|
|
45
|
-
export const materialize: Promise<unknown>;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
declare module '*.obj' {
|
|
49
|
-
import type { PackedScene } from '@ringozz/godot/PackedScene';
|
|
50
|
-
const asset: Promise<PackedScene>;
|
|
51
|
-
export default asset;
|
|
52
|
-
export const materialize: Promise<unknown>;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
declare module '*.jpg' {
|
|
56
|
-
import type { CompressedTexture2D } from '@ringozz/godot/CompressedTexture2D';
|
|
57
|
-
const asset: Promise<CompressedTexture2D>;
|
|
58
|
-
export default asset;
|
|
59
|
-
export const materialize: Promise<unknown>;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
declare module '*.jpeg' {
|
|
63
|
-
import type { CompressedTexture2D } from '@ringozz/godot/CompressedTexture2D';
|
|
64
|
-
const asset: Promise<CompressedTexture2D>;
|
|
65
|
-
export default asset;
|
|
66
|
-
export const materialize: Promise<unknown>;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
declare module '*.png' {
|
|
70
|
-
import type { CompressedTexture2D } from '@ringozz/godot/CompressedTexture2D';
|
|
71
|
-
const asset: Promise<CompressedTexture2D>;
|
|
72
|
-
export default asset;
|
|
73
|
-
export const materialize: Promise<unknown>;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
declare module '*.webp' {
|
|
77
|
-
import type { CompressedTexture2D } from '@ringozz/godot/CompressedTexture2D';
|
|
78
|
-
const asset: Promise<CompressedTexture2D>;
|
|
79
|
-
export default asset;
|
|
80
|
-
export const materialize: Promise<unknown>;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
declare module '*.svg' {
|
|
84
|
-
import type { CompressedTexture2D } from '@ringozz/godot/CompressedTexture2D';
|
|
85
|
-
const asset: Promise<CompressedTexture2D>;
|
|
86
|
-
export default asset;
|
|
87
|
-
export const materialize: Promise<unknown>;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
declare module '*.exr' {
|
|
91
|
-
import type { TextureLayered } from '@ringozz/godot/TextureLayered';
|
|
92
|
-
const asset: Promise<TextureLayered>;
|
|
93
|
-
export default asset;
|
|
94
|
-
export const materialize: Promise<unknown>;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
declare module '*.hdr' {
|
|
98
|
-
import type { TextureLayered } from '@ringozz/godot/TextureLayered';
|
|
99
|
-
const asset: Promise<TextureLayered>;
|
|
100
|
-
export default asset;
|
|
101
|
-
export const materialize: Promise<unknown>;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
declare module '*.wav' {
|
|
105
|
-
import type { AudioStreamWAV } from '@ringozz/godot/AudioStreamWAV';
|
|
106
|
-
const asset: Promise<AudioStreamWAV>;
|
|
107
|
-
export default asset;
|
|
108
|
-
export const materialize: Promise<unknown>;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
declare module '*.ttf' {
|
|
112
|
-
import type { FontFile } from '@ringozz/godot/FontFile';
|
|
113
|
-
const asset: Promise<FontFile>;
|
|
114
|
-
export default asset;
|
|
115
|
-
export const materialize: Promise<unknown>;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
declare module '*.otf' {
|
|
119
|
-
import type { FontFile } from '@ringozz/godot/FontFile';
|
|
120
|
-
const asset: Promise<FontFile>;
|
|
121
|
-
export default asset;
|
|
122
|
-
export const materialize: Promise<unknown>;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
declare module '*.ogg' {
|
|
126
|
-
import type { AudioStreamOggVorbis } from '@ringozz/godot/AudioStreamOggVorbis';
|
|
127
|
-
const asset: Promise<AudioStreamOggVorbis>;
|
|
128
|
-
export default asset;
|
|
129
|
-
export const materialize: Promise<unknown>;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
declare module '*.mp3' {
|
|
133
|
-
import type { AudioStreamMP3 } from '@ringozz/godot/AudioStreamMP3';
|
|
134
|
-
const asset: Promise<AudioStreamMP3>;
|
|
135
|
-
export default asset;
|
|
136
|
-
export const materialize: Promise<unknown>;
|
|
137
|
-
}
|
|
20
|
+
declare module '*.tres' {
|
|
21
|
+
import type { Resource } from '@ringozz/godot/Resource';
|
|
22
|
+
const asset: Promise<Resource>;
|
|
23
|
+
export default asset;
|
|
24
|
+
export const materialize: Promise<unknown>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
declare module '*.po' {
|
|
28
|
+
import type { Translation } from '@ringozz/godot/Translation';
|
|
29
|
+
const asset: Promise<Translation>;
|
|
30
|
+
export default asset;
|
|
31
|
+
export const materialize: Promise<unknown>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
declare module '*.gltf' {
|
|
35
|
+
import type { PackedScene } from '@ringozz/godot/PackedScene';
|
|
36
|
+
const asset: Promise<PackedScene>;
|
|
37
|
+
export default asset;
|
|
38
|
+
export const materialize: Promise<unknown>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
declare module '*.tscn' {
|
|
42
|
+
import type { PackedScene } from '@ringozz/godot/PackedScene';
|
|
43
|
+
const asset: Promise<PackedScene>;
|
|
44
|
+
export default asset;
|
|
45
|
+
export const materialize: Promise<unknown>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
declare module '*.obj' {
|
|
49
|
+
import type { PackedScene } from '@ringozz/godot/PackedScene';
|
|
50
|
+
const asset: Promise<PackedScene>;
|
|
51
|
+
export default asset;
|
|
52
|
+
export const materialize: Promise<unknown>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
declare module '*.jpg' {
|
|
56
|
+
import type { CompressedTexture2D } from '@ringozz/godot/CompressedTexture2D';
|
|
57
|
+
const asset: Promise<CompressedTexture2D>;
|
|
58
|
+
export default asset;
|
|
59
|
+
export const materialize: Promise<unknown>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
declare module '*.jpeg' {
|
|
63
|
+
import type { CompressedTexture2D } from '@ringozz/godot/CompressedTexture2D';
|
|
64
|
+
const asset: Promise<CompressedTexture2D>;
|
|
65
|
+
export default asset;
|
|
66
|
+
export const materialize: Promise<unknown>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
declare module '*.png' {
|
|
70
|
+
import type { CompressedTexture2D } from '@ringozz/godot/CompressedTexture2D';
|
|
71
|
+
const asset: Promise<CompressedTexture2D>;
|
|
72
|
+
export default asset;
|
|
73
|
+
export const materialize: Promise<unknown>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
declare module '*.webp' {
|
|
77
|
+
import type { CompressedTexture2D } from '@ringozz/godot/CompressedTexture2D';
|
|
78
|
+
const asset: Promise<CompressedTexture2D>;
|
|
79
|
+
export default asset;
|
|
80
|
+
export const materialize: Promise<unknown>;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
declare module '*.svg' {
|
|
84
|
+
import type { CompressedTexture2D } from '@ringozz/godot/CompressedTexture2D';
|
|
85
|
+
const asset: Promise<CompressedTexture2D>;
|
|
86
|
+
export default asset;
|
|
87
|
+
export const materialize: Promise<unknown>;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
declare module '*.exr' {
|
|
91
|
+
import type { TextureLayered } from '@ringozz/godot/TextureLayered';
|
|
92
|
+
const asset: Promise<TextureLayered>;
|
|
93
|
+
export default asset;
|
|
94
|
+
export const materialize: Promise<unknown>;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
declare module '*.hdr' {
|
|
98
|
+
import type { TextureLayered } from '@ringozz/godot/TextureLayered';
|
|
99
|
+
const asset: Promise<TextureLayered>;
|
|
100
|
+
export default asset;
|
|
101
|
+
export const materialize: Promise<unknown>;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
declare module '*.wav' {
|
|
105
|
+
import type { AudioStreamWAV } from '@ringozz/godot/AudioStreamWAV';
|
|
106
|
+
const asset: Promise<AudioStreamWAV>;
|
|
107
|
+
export default asset;
|
|
108
|
+
export const materialize: Promise<unknown>;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
declare module '*.ttf' {
|
|
112
|
+
import type { FontFile } from '@ringozz/godot/FontFile';
|
|
113
|
+
const asset: Promise<FontFile>;
|
|
114
|
+
export default asset;
|
|
115
|
+
export const materialize: Promise<unknown>;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
declare module '*.otf' {
|
|
119
|
+
import type { FontFile } from '@ringozz/godot/FontFile';
|
|
120
|
+
const asset: Promise<FontFile>;
|
|
121
|
+
export default asset;
|
|
122
|
+
export const materialize: Promise<unknown>;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
declare module '*.ogg' {
|
|
126
|
+
import type { AudioStreamOggVorbis } from '@ringozz/godot/AudioStreamOggVorbis';
|
|
127
|
+
const asset: Promise<AudioStreamOggVorbis>;
|
|
128
|
+
export default asset;
|
|
129
|
+
export const materialize: Promise<unknown>;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
declare module '*.mp3' {
|
|
133
|
+
import type { AudioStreamMP3 } from '@ringozz/godot/AudioStreamMP3';
|
|
134
|
+
const asset: Promise<AudioStreamMP3>;
|
|
135
|
+
export default asset;
|
|
136
|
+
export const materialize: Promise<unknown>;
|
|
137
|
+
}
|