@threenative/core 0.2.0 → 0.3.1
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/LICENSE +21 -0
- package/README.md +55 -0
- package/capabilities.json +5292 -0
- package/dist/assets-kyoF7JlJ.d.ts +103 -0
- package/dist/audio-BFiGneTL.d.ts +156 -0
- package/dist/canvas-layer-BLVijiUJ.d.ts +62 -0
- package/dist/game-XGrTzapq.d.ts +1166 -0
- package/dist/gpu-readback-D2iRvoe9.d.ts +112 -0
- package/dist/hot.d.ts +20 -2
- package/dist/hot.js +14 -2
- package/dist/index.d.ts +2108 -55
- package/dist/index.js +15645 -2222
- package/dist/net.d.ts +65 -0
- package/dist/net.js +643 -0
- package/dist/playtest.d.ts +37 -4
- package/dist/playtest.js +246 -546
- package/dist/react.d.ts +177 -0
- package/dist/react.js +635 -0
- package/dist/renderer-C6hqZpoG.d.ts +770 -0
- package/dist/ui-layer.d.ts +306 -0
- package/dist/ui-layer.js +425 -0
- package/dist/world.d.ts +254 -0
- package/dist/world.js +2686 -0
- package/gpl/LICENSE.GPL +117 -0
- package/gpl/convert.py +192 -0
- package/gpl/recipes/_common.py +169 -0
- package/gpl/recipes/bake_ao.py +111 -0
- package/gpl/recipes/decimate.py +64 -0
- package/gpl/recipes/retarget.py +131 -0
- package/gpl/recipes/unwrap.py +71 -0
- package/mcp/assets.mjs +5 -0
- package/mcp/blender-server.mjs +632 -0
- package/mcp/blender.mjs +27 -0
- package/mcp/engine-server.mjs +501 -0
- package/mcp/engine.mjs +31 -0
- package/mcp/install.d.mts +37 -0
- package/mcp/install.mjs +145 -0
- package/mcp/launch.mjs +72 -0
- package/mcp/sculpt.mjs +5 -0
- package/mcp/servers.d.mts +34 -0
- package/mcp/servers.mjs +160 -0
- package/package.json +76 -6
- package/patches/three@0.185.1.patch +522 -0
- package/scripts/apply-three-patch.mjs +297 -0
- package/scripts/ensure-mcp.mjs +43 -0
- package/scripts/postinstall.mjs +6 -0
- package/dist/audio-CEAw0w5y.d.ts +0 -35
- package/dist/game-DRt1Qhq3.d.ts +0 -429
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
const THREE_VERSION = "0.185.1";
|
|
9
|
+
const PATCH_NAME = `three@${THREE_VERSION}.patch`;
|
|
10
|
+
|
|
11
|
+
/** Apply the package-owned Three.js patch to the dependency resolved for the consumer. */
|
|
12
|
+
export async function applyThreePatch(options = {}) {
|
|
13
|
+
const packageRoot =
|
|
14
|
+
options.packageRoot ?? path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
15
|
+
const consumerRoot = path.resolve(
|
|
16
|
+
options.consumerRoot ??
|
|
17
|
+
process.env.INIT_CWD ??
|
|
18
|
+
process.env.npm_config_local_prefix ??
|
|
19
|
+
process.cwd(),
|
|
20
|
+
);
|
|
21
|
+
const threeRoot = options.threeRoot ?? resolveThreeRoot(consumerRoot, packageRoot);
|
|
22
|
+
const manifestPath = path.join(threeRoot, "package.json");
|
|
23
|
+
const manifest = await readJson(manifestPath, "Three.js package manifest");
|
|
24
|
+
if (manifest.name !== "three" || manifest.version !== THREE_VERSION) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`TN_THREE_PATCH_VERSION: expected three@${THREE_VERSION}, found ${String(manifest.name)}@${String(manifest.version)} at ${manifestPath}.`,
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const patchPath = path.join(packageRoot, "patches", PATCH_NAME);
|
|
31
|
+
const patch = parsePatch(await readFile(patchPath, "utf8"), patchPath);
|
|
32
|
+
const plans = await planPatch(threeRoot, patch);
|
|
33
|
+
if (plans.every((plan) => plan.status === "patched")) return "unchanged";
|
|
34
|
+
if (plans.some((plan) => plan.status !== "stock")) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`TN_THREE_PATCH_PARTIAL: ${manifestPath} is neither stock nor fully patched; refusing to modify a partial installation.`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
for (const plan of plans) await writeFile(plan.file, plan.contents, "utf8");
|
|
41
|
+
return "patched";
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function resolveThreeRoot(consumerRoot, packageRoot) {
|
|
45
|
+
const attempted = [];
|
|
46
|
+
for (const root of [packageRoot, consumerRoot]) {
|
|
47
|
+
try {
|
|
48
|
+
const resolver = createRequire(path.join(root, "package.json"));
|
|
49
|
+
const entry = resolver.resolve("three");
|
|
50
|
+
const resolvedRoot = findPackageRoot(entry);
|
|
51
|
+
if (!isWithinModuleSearchPath(resolvedRoot, root)) {
|
|
52
|
+
throw new Error(`resolved outside local module paths: ${resolvedRoot}`);
|
|
53
|
+
}
|
|
54
|
+
return resolvedRoot;
|
|
55
|
+
} catch (error) {
|
|
56
|
+
attempted.push(`${root}: ${error instanceof Error ? error.message : String(error)}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
throw new Error(`TN_THREE_PATCH_MISSING: could not resolve three from ${attempted.join("; ")}.`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function isWithinModuleSearchPath(candidate, root) {
|
|
63
|
+
return moduleSearchPaths(root).some((searchPath) => isWithinRoot(candidate, searchPath));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function moduleSearchPaths(root) {
|
|
67
|
+
const paths = [];
|
|
68
|
+
let current = path.resolve(root);
|
|
69
|
+
while (true) {
|
|
70
|
+
if (path.basename(current) !== "node_modules") paths.push(path.join(current, "node_modules"));
|
|
71
|
+
const parent = path.dirname(current);
|
|
72
|
+
if (parent === current) return paths;
|
|
73
|
+
current = parent;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function isWithinRoot(candidate, root) {
|
|
78
|
+
const relative = path.relative(root, candidate);
|
|
79
|
+
return (
|
|
80
|
+
relative === "" ||
|
|
81
|
+
(relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative))
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function findPackageRoot(entry) {
|
|
86
|
+
let current = path.dirname(entry);
|
|
87
|
+
while (true) {
|
|
88
|
+
if (existsSync(path.join(current, "package.json"))) return current;
|
|
89
|
+
const parent = path.dirname(current);
|
|
90
|
+
if (parent === current) break;
|
|
91
|
+
current = parent;
|
|
92
|
+
}
|
|
93
|
+
throw new Error(`TN_THREE_PATCH_MISSING: resolved three entry has no package.json: ${entry}.`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function readJson(file, description) {
|
|
97
|
+
let text;
|
|
98
|
+
try {
|
|
99
|
+
text = await readFile(file, "utf8");
|
|
100
|
+
} catch (error) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`TN_THREE_PATCH_MISSING: could not read ${description} at ${file}: ${String(error)}.`,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
return JSON.parse(text);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
throw new Error(
|
|
109
|
+
`TN_THREE_PATCH_INVALID: ${description} at ${file} is not valid JSON: ${String(error)}.`,
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function parsePatch(text, patchPath) {
|
|
115
|
+
const files = parsePatchFiles(text, patchPath);
|
|
116
|
+
if (files.length === 0)
|
|
117
|
+
throw new Error(`TN_THREE_PATCH_INVALID: no file patches in ${patchPath}.`);
|
|
118
|
+
for (const file of files) {
|
|
119
|
+
validatePatchFile(file, patchPath);
|
|
120
|
+
}
|
|
121
|
+
return files;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function parsePatchFiles(text, patchPath) {
|
|
125
|
+
const files = [];
|
|
126
|
+
let current;
|
|
127
|
+
let hunk;
|
|
128
|
+
for (const line of text.replaceAll("\r\n", "\n").split("\n")) {
|
|
129
|
+
if (line.startsWith("diff --git ")) {
|
|
130
|
+
if (current !== undefined) files.push(finishPatchFile(current, patchPath));
|
|
131
|
+
current = { hunks: [], oldPath: undefined, newPath: undefined };
|
|
132
|
+
hunk = undefined;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (current === undefined) continue;
|
|
136
|
+
hunk = parsePatchLine(line, current, hunk, patchPath);
|
|
137
|
+
}
|
|
138
|
+
if (current !== undefined) files.push(finishPatchFile(current, patchPath));
|
|
139
|
+
return files;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function parsePatchLine(line, current, hunk, patchPath) {
|
|
143
|
+
if (line.startsWith("--- ")) {
|
|
144
|
+
current.oldPath = patchPathFromHeader(line.slice(4), patchPath);
|
|
145
|
+
return hunk;
|
|
146
|
+
}
|
|
147
|
+
if (line.startsWith("+++ ")) {
|
|
148
|
+
current.newPath = patchPathFromHeader(line.slice(4), patchPath);
|
|
149
|
+
return hunk;
|
|
150
|
+
}
|
|
151
|
+
const parsedHunk = parsePatchHunk(line);
|
|
152
|
+
if (parsedHunk !== undefined) {
|
|
153
|
+
current.hunks.push(parsedHunk);
|
|
154
|
+
return parsedHunk;
|
|
155
|
+
}
|
|
156
|
+
if (line !== "\" && hunk !== undefined && isPatchLine(line))
|
|
157
|
+
hunk.lines.push(line);
|
|
158
|
+
return hunk;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function finishPatchFile(file, patchPath) {
|
|
162
|
+
if (file.oldPath === undefined || file.newPath === undefined || file.hunks.length === 0) {
|
|
163
|
+
throw new Error(`TN_THREE_PATCH_INVALID: incomplete file patch in ${patchPath}.`);
|
|
164
|
+
}
|
|
165
|
+
if (file.oldPath !== file.newPath) {
|
|
166
|
+
throw new Error(`TN_THREE_PATCH_INVALID: rename patches are not supported in ${patchPath}.`);
|
|
167
|
+
}
|
|
168
|
+
return file;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function parsePatchHunk(line) {
|
|
172
|
+
const header = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/u.exec(line);
|
|
173
|
+
if (header === null) return undefined;
|
|
174
|
+
return {
|
|
175
|
+
lines: [],
|
|
176
|
+
newCount: Number(header[4] ?? 1),
|
|
177
|
+
newStart: Number(header[3]),
|
|
178
|
+
oldCount: Number(header[2] ?? 1),
|
|
179
|
+
oldStart: Number(header[1]),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function isPatchLine(line) {
|
|
184
|
+
return line[0] === " " || line[0] === "+" || line[0] === "-";
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function validatePatchFile(file, patchPath) {
|
|
188
|
+
for (const candidate of file.hunks) {
|
|
189
|
+
const oldCount = candidate.lines.filter((line) => line[0] === " " || line[0] === "-").length;
|
|
190
|
+
const newCount = candidate.lines.filter((line) => line[0] === " " || line[0] === "+").length;
|
|
191
|
+
if (oldCount !== candidate.oldCount || newCount !== candidate.newCount) {
|
|
192
|
+
throw new Error(`TN_THREE_PATCH_INVALID: hunk line counts do not match in ${patchPath}.`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function patchPathFromHeader(header, patchPath) {
|
|
198
|
+
const value = header.trim().split(/\s+/u)[0];
|
|
199
|
+
if (value === undefined || (!value.startsWith("a/") && !value.startsWith("b/"))) {
|
|
200
|
+
throw new Error(`TN_THREE_PATCH_INVALID: unsupported file path in ${patchPath}.`);
|
|
201
|
+
}
|
|
202
|
+
const relative = value.slice(2);
|
|
203
|
+
if (relative.length === 0 || relative.split("/").some((part) => part === ".." || part === "")) {
|
|
204
|
+
throw new Error(`TN_THREE_PATCH_INVALID: unsafe file path '${value}' in ${patchPath}.`);
|
|
205
|
+
}
|
|
206
|
+
return relative;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async function planPatch(threeRoot, files) {
|
|
210
|
+
const plans = [];
|
|
211
|
+
for (const file of files) {
|
|
212
|
+
const target = path.resolve(threeRoot, file.oldPath);
|
|
213
|
+
if (path.relative(threeRoot, target).startsWith(`..${path.sep}`)) {
|
|
214
|
+
throw new Error(
|
|
215
|
+
`TN_THREE_PATCH_INVALID: patch escapes the Three.js package: ${file.oldPath}.`,
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
const original = await readFile(target, "utf8");
|
|
219
|
+
const lines = original.replaceAll("\r\n", "\n").split("\n");
|
|
220
|
+
const status = classifyFile(lines, file.hunks);
|
|
221
|
+
if (status === "patched") {
|
|
222
|
+
plans.push({ contents: original, file: target, status });
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
if (status !== "stock") {
|
|
226
|
+
throw new Error(
|
|
227
|
+
`TN_THREE_PATCH_PARTIAL: hunk state is mixed in ${target}; refusing to modify a partial installation.`,
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
plans.push({ contents: applyFile(lines, file.hunks, target).join("\n"), file: target, status });
|
|
231
|
+
}
|
|
232
|
+
return plans;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function classifyFile(lines, hunks) {
|
|
236
|
+
let stock = true;
|
|
237
|
+
let patched = true;
|
|
238
|
+
let offset = 0;
|
|
239
|
+
for (const hunk of hunks) {
|
|
240
|
+
const oldLines = hunk.lines
|
|
241
|
+
.filter((line) => line[0] === " " || line[0] === "-")
|
|
242
|
+
.map((line) => line.slice(1));
|
|
243
|
+
const newLines = hunk.lines
|
|
244
|
+
.filter((line) => line[0] === " " || line[0] === "+")
|
|
245
|
+
.map((line) => line.slice(1));
|
|
246
|
+
if (locate(lines, oldLines, hunk.oldStart - 1 + offset) === undefined) stock = false;
|
|
247
|
+
if (locate(lines, newLines, hunk.newStart - 1) === undefined) patched = false;
|
|
248
|
+
offset += newLines.length - oldLines.length;
|
|
249
|
+
}
|
|
250
|
+
if (stock) return "stock";
|
|
251
|
+
if (patched) return "patched";
|
|
252
|
+
return "mixed";
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function applyFile(lines, hunks, file) {
|
|
256
|
+
const result = [...lines];
|
|
257
|
+
let offset = 0;
|
|
258
|
+
for (const hunk of hunks) {
|
|
259
|
+
const oldLines = hunk.lines
|
|
260
|
+
.filter((line) => line[0] === " " || line[0] === "-")
|
|
261
|
+
.map((line) => line.slice(1));
|
|
262
|
+
const newLines = hunk.lines
|
|
263
|
+
.filter((line) => line[0] === " " || line[0] === "+")
|
|
264
|
+
.map((line) => line.slice(1));
|
|
265
|
+
const index = locate(result, oldLines, hunk.oldStart - 1 + offset);
|
|
266
|
+
if (index === undefined) {
|
|
267
|
+
throw new Error(`TN_THREE_PATCH_INVALID: stock hunk no longer matches ${file}.`);
|
|
268
|
+
}
|
|
269
|
+
result.splice(index, oldLines.length, ...newLines);
|
|
270
|
+
offset += newLines.length - oldLines.length;
|
|
271
|
+
}
|
|
272
|
+
return result;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function locate(lines, expected, preferred) {
|
|
276
|
+
const candidates = [];
|
|
277
|
+
for (let index = 0; index <= lines.length - expected.length; index += 1) {
|
|
278
|
+
if (expected.every((line, offset) => lines[index + offset] === line)) candidates.push(index);
|
|
279
|
+
}
|
|
280
|
+
if (candidates.length === 0) return undefined;
|
|
281
|
+
candidates.sort((left, right) => Math.abs(left - preferred) - Math.abs(right - preferred));
|
|
282
|
+
if (
|
|
283
|
+
candidates.length > 1 &&
|
|
284
|
+
Math.abs(candidates[0] - preferred) === Math.abs(candidates[1] - preferred)
|
|
285
|
+
) {
|
|
286
|
+
throw new Error(
|
|
287
|
+
`TN_THREE_PATCH_INVALID: ambiguous hunk location near line ${String(preferred + 1)}.`,
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
return candidates[0];
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const entry = process.argv[1];
|
|
294
|
+
if (entry !== undefined && path.resolve(entry) === path.resolve(fileURLToPath(import.meta.url))) {
|
|
295
|
+
const result = await applyThreePatch();
|
|
296
|
+
process.stdout.write(`threenative: Three.js velocity patch ${result}\n`);
|
|
297
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
// Installing ThreeNative wires its MCP servers into the project. An agent authoring a game here
|
|
5
|
+
// should not have to be told the asset, sculpt and capability tools exist, or run a setup command
|
|
6
|
+
// to get them. Every host that reads a project-scoped MCP config gets one — `MCP_HOSTS` is the
|
|
7
|
+
// list. Set THREENATIVE_SKIP_MCP_SETUP=1 to opt out.
|
|
8
|
+
import { MCP_HOSTS, ensureHostMcpConfigs, installTarget } from "../mcp/install.mjs";
|
|
9
|
+
|
|
10
|
+
const LABELS = new Map(MCP_HOSTS.map((host) => [host.id, host.label]));
|
|
11
|
+
|
|
12
|
+
export function runMcpSetup(environment = process.env, cwd = process.cwd()) {
|
|
13
|
+
const skip = environment.THREENATIVE_SKIP_MCP_SETUP;
|
|
14
|
+
if (skip === "1" || skip === "true") return;
|
|
15
|
+
// Never fail an install over this. A game that cannot write its MCP configs still runs.
|
|
16
|
+
try {
|
|
17
|
+
const target = installTarget(environment, cwd);
|
|
18
|
+
if (target === undefined) return;
|
|
19
|
+
const outcomes = ensureHostMcpConfigs(target);
|
|
20
|
+
const wired = [...outcomes]
|
|
21
|
+
.filter(([, outcome]) => outcome === "created" || outcome === "updated")
|
|
22
|
+
.map(([id]) => LABELS.get(id) ?? id);
|
|
23
|
+
if (wired.length > 0) {
|
|
24
|
+
process.stdout.write(
|
|
25
|
+
`threenative: wired the ThreeNative MCP servers for ${wired.join(", ")}\n`,
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
const unreadable = [...outcomes]
|
|
29
|
+
.filter(([, outcome]) => outcome === "unreadable")
|
|
30
|
+
.map(([id]) => LABELS.get(id) ?? id);
|
|
31
|
+
if (unreadable.length > 0) {
|
|
32
|
+
process.stdout.write(
|
|
33
|
+
`threenative: left ${unreadable.join(", ")} alone; its config is not valid JSON\n`,
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
} catch (error) {
|
|
37
|
+
process.stdout.write(`threenative: could not wire the MCP configs (${error})\n`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const entry = process.argv[1];
|
|
42
|
+
if (entry !== undefined && pathToFileURL(path.resolve(entry)).href === import.meta.url)
|
|
43
|
+
runMcpSetup();
|
package/dist/audio-CEAw0w5y.d.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { AudioListener, Object3D, Audio, Vector3, PositionalAudio } from 'three';
|
|
2
|
-
|
|
3
|
-
interface IAudioBusOptions {
|
|
4
|
-
readonly camera: Object3D;
|
|
5
|
-
readonly gestureTarget?: EventTarget;
|
|
6
|
-
readonly listener?: AudioListener;
|
|
7
|
-
readonly source?: () => EventTarget | undefined;
|
|
8
|
-
}
|
|
9
|
-
interface IAudioPlayOptions {
|
|
10
|
-
readonly fade?: number;
|
|
11
|
-
readonly loop?: boolean;
|
|
12
|
-
readonly volume?: number;
|
|
13
|
-
}
|
|
14
|
-
interface IAudioRuntimeSnapshot {
|
|
15
|
-
readonly queued: number;
|
|
16
|
-
readonly voices: number;
|
|
17
|
-
}
|
|
18
|
-
declare class AudioBus {
|
|
19
|
-
#private;
|
|
20
|
-
readonly listener: AudioListener;
|
|
21
|
-
constructor(options: IAudioBusOptions);
|
|
22
|
-
get queued(): number;
|
|
23
|
-
get voices(): number;
|
|
24
|
-
setCamera(camera: Object3D): void;
|
|
25
|
-
reparent(camera: Object3D): void;
|
|
26
|
-
unlock(): Promise<void>;
|
|
27
|
-
play(buffer: AudioBuffer, options?: IAudioPlayOptions): Audio;
|
|
28
|
-
playAt(buffer: AudioBuffer, source: Object3D | Vector3, options?: IAudioPlayOptions): PositionalAudio;
|
|
29
|
-
music(buffer: AudioBuffer, options?: IAudioPlayOptions): Audio;
|
|
30
|
-
stop(): void;
|
|
31
|
-
dispose(): void;
|
|
32
|
-
}
|
|
33
|
-
declare function audioRuntimeSnapshot(): IAudioRuntimeSnapshot;
|
|
34
|
-
|
|
35
|
-
export { AudioBus as A, type IAudioBusOptions as I, audioRuntimeSnapshot as a, type IAudioPlayOptions as b };
|