@drawcall/lod 0.5.4 → 0.5.5
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/dist/loader/node.js +13 -7
- package/dist/loader/node.js.map +1 -1
- package/package.json +1 -1
package/dist/loader/node.js
CHANGED
|
@@ -76,11 +76,17 @@ class SessionLoader extends BrowserCachedLodLoader {
|
|
|
76
76
|
publicPath(url) {
|
|
77
77
|
return url.startsWith(`${placeholderOrigin}/`) ? url.slice(placeholderOrigin.length) : super.publicPath(url);
|
|
78
78
|
}
|
|
79
|
-
/**
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Load `url` in the load's session, or, once `loadAsync` has resolved, in a session of its own. In a process without a
|
|
81
|
+
* document, on the canvas's platform: three's loaders report progress with ProgressEvent and decode images, which Node
|
|
82
|
+
* has not.
|
|
83
|
+
*/
|
|
84
|
+
async loadAsset(url) {
|
|
85
|
+
if (!sessions.getStore())
|
|
86
|
+
return session({ read: new Set(), packages: new Set() }, () => this.loadAsset(url));
|
|
87
|
+
if (typeof document === "undefined")
|
|
88
|
+
await canvas();
|
|
89
|
+
return super.loadAsset(url);
|
|
84
90
|
}
|
|
85
91
|
async newBakeRenderer() {
|
|
86
92
|
// A process with a document, such as a glts host's, has WebGPU of its own: bake on a canvas of that document, as a
|
|
@@ -180,8 +186,8 @@ async function session(state, run) {
|
|
|
180
186
|
}
|
|
181
187
|
}
|
|
182
188
|
/**
|
|
183
|
-
* The served fetch, and a canvas of @drawcall/webgpu once a session bakes, which installs WebGPU,
|
|
184
|
-
* workers while it lives.
|
|
189
|
+
* The served fetch, and a canvas of @drawcall/webgpu once a session loads a source or bakes, which installs WebGPU,
|
|
190
|
+
* image decoding and workers while it lives.
|
|
185
191
|
*/
|
|
186
192
|
function install() {
|
|
187
193
|
const { fetch } = globalThis;
|
package/dist/loader/node.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/loader/node.ts"],"names":[],"mappings":"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","sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { readFile } from \"node:fs/promises\";\nimport { fileURLToPath } from \"node:url\";\nimport { createCanvas, type Canvas } from \"@drawcall/webgpu\";\nimport type { GLTSLoader } from \"@drawcall/glts\";\nimport { resolve as resolveImport } from \"import-meta-resolve\";\nimport { Loader, LoadingManager, WebGPURenderer, type Object3D } from \"three/webgpu\";\nimport { publicURL, type Input } from \"vitecache\";\nimport { createBakeRenderer, setUpBakeRenderer } from \"../bake.js\";\nimport type { LodLevel } from \"../levels/index.js\";\nimport { CachedLodLoader as BrowserCachedLodLoader, type CachedLodLoaderOptions } from \"./index.js\";\nimport type { LodRequest } from \"./request.js\";\nimport { loaderPathURL, placeholderOrigin } from \"./url.js\";\n\ninterface Session {\n /** The `file:` URLs of the public files the session's loads read. */\n read: Set<string>;\n /** The installed packages the session's .glts sources import. */\n packages: Set<string>;\n}\n\n/** The session of each load, by its async context: the served fetch is global. */\nconst sessions = new AsyncLocalStorage<Session>();\n\n/**\n * CachedLodLoader in Node, as the vitecache plugin and the glts CLI run it: `loadAsync` builds and saves every level of\n * the ladder, each with the public files the ladder's loads read and the installed versions of three and of the\n * packages its .glts sources import. A load that reads anything else, such as a URL off the public directory or a module\n * a .glts source imports from a CDN, fails, since no stored level could be checked against it. Served paths such as\n * `/trees/oak.glts`, and `file:` URLs in the public directory, as a headless .glts script's manager resolves them to,\n * load from vitecache's public directory (see `publicURL`), and `.glts` sources through a GLTSLoader of the load's own;\n * bakes draw on a canvas of the process's document, as a glts host has one, or else on a WebGPU device of\n * @drawcall/webgpu. The manager only resolves the request's URL.\n *\n * Each `loadAsync` loads and bakes with what it makes for itself, which it frees before resolving, so loads may run\n * concurrently. The levels it returns load their stored bytes as in browsers, and none holds the source: the source\n * level, and a simplified level, which draws with the source's materials, load the source again when a camera needs\n * them, as the glts CLI's renders of a .glts script that draws a Lod do.\n */\nexport class CachedLodLoader extends BrowserCachedLodLoader {\n constructor(manager?: LoadingManager, options: CachedLodLoaderOptions = {}) {\n super(manager, options);\n }\n\n override loadAsync(request: LodRequest): Promise<LodLevel[]> {\n const input = typeof request === \"string\" ? { url: request } : request;\n const url = this.publicPath(this.manager.resolveURL(loaderPathURL(input.url, this.path)));\n return session({ read: new Set(), packages: new Set() }, async () => {\n const loader = new SessionLoader(this.options);\n try {\n return await loader.loadAsync({ ...input, url });\n } finally {\n await loader.dispose();\n }\n });\n }\n\n /** Nothing to free: each load frees what it made. */\n override async dispose(): Promise<void> {}\n\n /** A `file:` URL in the public directory as its served path; others as in browsers. */\n protected override publicPath(url: string): string {\n if (!url.startsWith(\"file:\")) return super.publicPath(url);\n const base = publicURL(\"/\");\n if (!url.startsWith(base)) throw new Error(`CachedLodLoader: cannot precompute \"${url}\", which lies outside the public directory ${base}`);\n return `/${url.slice(base.length)}`;\n }\n}\n\n/** One `loadAsync` of the Node loader: builds every level, with a GLTSLoader and bake renderer of its own. */\nclass SessionLoader extends BrowserCachedLodLoader {\n protected override readonly buildsAll = true;\n private readonly scripts: ScriptLoader;\n\n constructor(options: CachedLodLoaderOptions) {\n super(servingManager(), options);\n // Packages resolve as the app's do.\n this.scripts = new ScriptLoader(this.manager, publicURL(\"/\"));\n this.manager.addHandler(/\\.glts$/i, this.scripts);\n }\n\n override async dispose(): Promise<void> {\n await super.dispose();\n await this.scripts.dispose();\n }\n\n /**\n * A path its manager served at the placeholder origin as that path, which `CachedLodLoader.loadAsync` gave below the\n * app's base: keyed as in browsers whatever document the process has, such as the one a headless GLTS renderer\n * installs, against which the placeholder origin would be foreign.\n */\n protected override publicPath(url: string): string {\n return url.startsWith(`${placeholderOrigin}/`) ? url.slice(placeholderOrigin.length) : super.publicPath(url);\n }\n\n /** Load `url` in the load's session, or, once `loadAsync` has resolved, in a session of its own. */\n protected override loadAsset(url: string): Promise<Object3D> {\n if (sessions.getStore()) return super.loadAsset(url);\n return session({ read: new Set(), packages: new Set() }, () => super.loadAsset(url));\n }\n\n protected override async newBakeRenderer(): Promise<WebGPURenderer> {\n // A process with a document, such as a glts host's, has WebGPU of its own: bake on a canvas of that document, as a\n // .glts script does. A second WebGPU runtime beside the host's would take over globals the host's images upload with.\n if (typeof document !== \"undefined\") return createBakeRenderer();\n // Three's DOM canvas types exclude native canvases; its constructor checks the actual API.\n const renderer: unknown = Reflect.construct(WebGPURenderer, [{ canvas: await canvas(), antialias: false }]);\n if (!(renderer instanceof WebGPURenderer)) throw new Error(\"CachedLodLoader: three did not make a WebGPURenderer\");\n return setUpBakeRenderer(renderer);\n }\n\n protected override inputs(): Input[] {\n const state = sessions.getStore();\n if (!state) throw new Error(\"CachedLodLoader: a level was built outside loadAsync\");\n // three builds every level, whatever its source imports.\n const packages = [...new Set([\"three\", ...state.packages])].sort();\n return [...[...state.read].sort().map((path) => ({ path })), ...packages.map((name) => ({ package: name }))];\n }\n}\n\n/** A manager that serves root-relative paths from the public directory while a load runs. */\nfunction servingManager(): LoadingManager {\n const manager = new LoadingManager();\n manager.setURLModifier((url) => {\n if (!url.startsWith(\"/\") || url.startsWith(\"//\")) return url;\n if (!sessions.getStore()) throw new Error(`CachedLodLoader: cannot load \"${url}\" once the load that asked for it has ended`);\n return placeholderOrigin + url;\n });\n return manager;\n}\n\n/**\n * Loads `.glts` sources with a GLTSLoader made at the first load, resolving their packages as the app at `root` does,\n * and records the packages each imports.\n */\nclass ScriptLoader extends Loader<Object3D> {\n private loader: Promise<GLTSLoader> | undefined;\n\n constructor(\n manager: LoadingManager,\n private readonly root: string,\n ) {\n super(manager);\n }\n\n override async loadAsync(url: string): Promise<Object3D> {\n this.loader ??= import(\"@drawcall/glts\").then(\n ({ GLTSLoader }) => new GLTSLoader(this.manager, { resolve: (specifier) => resolveImport(specifier, this.root) }),\n );\n const scene = await (await this.loader).loadAsync(url);\n const { packages, runtimeModules } = scene.source;\n if (runtimeModules.length > 0)\n throw new Error(\n `CachedLodLoader: cannot precompute \"${url}\": it imports ${runtimeModules.join(\", \")} from a CDN at runtime, which a stored level cannot be checked against`,\n );\n const state = sessions.getStore();\n if (!state) throw new Error(`CachedLodLoader: \"${url}\" loaded outside loadAsync`);\n for (const name of packages) state.packages.add(name);\n return scene;\n }\n\n /** Free the GLTSLoader and the scenes it loaded, resolving once freed; the next load makes another. */\n async dispose(): Promise<void> {\n const loader = this.loader;\n this.loader = undefined;\n // A GLTSLoader that failed to load failed the load that made it.\n const made = await loader?.catch(() => undefined);\n made?.dispose();\n }\n}\n\nlet users = 0;\n/** What sessions install while any runs: the served fetch, and the canvas once one bakes. */\nlet installed: Promise<Install> | undefined;\n/**\n * The restore of the last sessions to finish, which the next install waits for: @drawcall/webgpu saves and restores\n * the globals it installs per canvas, so two canvases' lives must not overlap.\n */\nlet restored: Promise<void> = Promise.resolve();\nlet current: Install | undefined;\n\ninterface Install {\n /**\n * The canvas bakes draw on in a process without a document, made by the first bake, so loads that only read stored\n * levels or load sources install no WebGPU runtime.\n */\n canvas?: Promise<Canvas>;\n restore: () => Promise<void>;\n}\n\n/** The canvas of the sessions running. */\nfunction canvas(): Promise<Canvas> {\n if (!current) throw new Error(\"CachedLodLoader: baking outside loadAsync\");\n return (current.canvas ??= createCanvas(1, 1));\n}\n\nasync function session<T>(state: Session, run: () => Promise<T>): Promise<T> {\n users++;\n // A failed restore failed the session that ran it. Sessions running together share one install.\n const shared = (installed ??= restored.catch(() => {}).then(install));\n try {\n current = await shared;\n return await sessions.run(state, run);\n } finally {\n if (--users === 0) {\n installed = current = undefined;\n // A failed install failed the run above.\n restored = shared.then(\n ({ restore }) => restore(),\n () => {},\n );\n await restored;\n }\n }\n}\n\n/**\n * The served fetch, and a canvas of @drawcall/webgpu once a session bakes, which installs WebGPU, image decoding and\n * workers while it lives.\n */\nfunction install(): Install {\n const { fetch } = globalThis;\n globalThis.fetch = (input, init) => serve(fetch, input, init);\n const made: Install = {\n restore: async () => {\n globalThis.fetch = fetch;\n // A canvas that failed to make failed the bake that made it.\n const canvas = await made.canvas?.catch(() => undefined);\n await canvas?.dispose();\n },\n };\n return made;\n}\n\nasync function serve(fetch: typeof globalThis.fetch, input: RequestInfo | URL, init?: RequestInit): Promise<Response> {\n const url = new URL(input instanceof Request ? input.url : input);\n const state = sessions.getStore();\n if (!state || url.protocol === \"data:\" || url.protocol === \"blob:\") return fetch(input, init);\n if (url.origin !== placeholderOrigin)\n throw new Error(`CachedLodLoader: cannot precompute a load that fetches ${url.href}, which a stored level cannot be checked against`);\n const file = publicURL(url.pathname);\n try {\n const bytes = await readFile(fileURLToPath(file));\n state.read.add(file);\n return new Response(bytes);\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") return new Response(null, { status: 404 });\n throw error;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/loader/node.ts"],"names":[],"mappings":"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","sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { readFile } from \"node:fs/promises\";\nimport { fileURLToPath } from \"node:url\";\nimport { createCanvas, type Canvas } from \"@drawcall/webgpu\";\nimport type { GLTSLoader } from \"@drawcall/glts\";\nimport { resolve as resolveImport } from \"import-meta-resolve\";\nimport { Loader, LoadingManager, WebGPURenderer, type Object3D } from \"three/webgpu\";\nimport { publicURL, type Input } from \"vitecache\";\nimport { createBakeRenderer, setUpBakeRenderer } from \"../bake.js\";\nimport type { LodLevel } from \"../levels/index.js\";\nimport { CachedLodLoader as BrowserCachedLodLoader, type CachedLodLoaderOptions } from \"./index.js\";\nimport type { LodRequest } from \"./request.js\";\nimport { loaderPathURL, placeholderOrigin } from \"./url.js\";\n\ninterface Session {\n /** The `file:` URLs of the public files the session's loads read. */\n read: Set<string>;\n /** The installed packages the session's .glts sources import. */\n packages: Set<string>;\n}\n\n/** The session of each load, by its async context: the served fetch is global. */\nconst sessions = new AsyncLocalStorage<Session>();\n\n/**\n * CachedLodLoader in Node, as the vitecache plugin and the glts CLI run it: `loadAsync` builds and saves every level of\n * the ladder, each with the public files the ladder's loads read and the installed versions of three and of the\n * packages its .glts sources import. A load that reads anything else, such as a URL off the public directory or a module\n * a .glts source imports from a CDN, fails, since no stored level could be checked against it. Served paths such as\n * `/trees/oak.glts`, and `file:` URLs in the public directory, as a headless .glts script's manager resolves them to,\n * load from vitecache's public directory (see `publicURL`), and `.glts` sources through a GLTSLoader of the load's own;\n * bakes draw on a canvas of the process's document, as a glts host has one, or else on a WebGPU device of\n * @drawcall/webgpu. The manager only resolves the request's URL.\n *\n * Each `loadAsync` loads and bakes with what it makes for itself, which it frees before resolving, so loads may run\n * concurrently. The levels it returns load their stored bytes as in browsers, and none holds the source: the source\n * level, and a simplified level, which draws with the source's materials, load the source again when a camera needs\n * them, as the glts CLI's renders of a .glts script that draws a Lod do.\n */\nexport class CachedLodLoader extends BrowserCachedLodLoader {\n constructor(manager?: LoadingManager, options: CachedLodLoaderOptions = {}) {\n super(manager, options);\n }\n\n override loadAsync(request: LodRequest): Promise<LodLevel[]> {\n const input = typeof request === \"string\" ? { url: request } : request;\n const url = this.publicPath(this.manager.resolveURL(loaderPathURL(input.url, this.path)));\n return session({ read: new Set(), packages: new Set() }, async () => {\n const loader = new SessionLoader(this.options);\n try {\n return await loader.loadAsync({ ...input, url });\n } finally {\n await loader.dispose();\n }\n });\n }\n\n /** Nothing to free: each load frees what it made. */\n override async dispose(): Promise<void> {}\n\n /** A `file:` URL in the public directory as its served path; others as in browsers. */\n protected override publicPath(url: string): string {\n if (!url.startsWith(\"file:\")) return super.publicPath(url);\n const base = publicURL(\"/\");\n if (!url.startsWith(base)) throw new Error(`CachedLodLoader: cannot precompute \"${url}\", which lies outside the public directory ${base}`);\n return `/${url.slice(base.length)}`;\n }\n}\n\n/** One `loadAsync` of the Node loader: builds every level, with a GLTSLoader and bake renderer of its own. */\nclass SessionLoader extends BrowserCachedLodLoader {\n protected override readonly buildsAll = true;\n private readonly scripts: ScriptLoader;\n\n constructor(options: CachedLodLoaderOptions) {\n super(servingManager(), options);\n // Packages resolve as the app's do.\n this.scripts = new ScriptLoader(this.manager, publicURL(\"/\"));\n this.manager.addHandler(/\\.glts$/i, this.scripts);\n }\n\n override async dispose(): Promise<void> {\n await super.dispose();\n await this.scripts.dispose();\n }\n\n /**\n * A path its manager served at the placeholder origin as that path, which `CachedLodLoader.loadAsync` gave below the\n * app's base: keyed as in browsers whatever document the process has, such as the one a headless GLTS renderer\n * installs, against which the placeholder origin would be foreign.\n */\n protected override publicPath(url: string): string {\n return url.startsWith(`${placeholderOrigin}/`) ? url.slice(placeholderOrigin.length) : super.publicPath(url);\n }\n\n /**\n * Load `url` in the load's session, or, once `loadAsync` has resolved, in a session of its own. In a process without a\n * document, on the canvas's platform: three's loaders report progress with ProgressEvent and decode images, which Node\n * has not.\n */\n protected override async loadAsset(url: string): Promise<Object3D> {\n if (!sessions.getStore()) return session({ read: new Set(), packages: new Set() }, () => this.loadAsset(url));\n if (typeof document === \"undefined\") await canvas();\n return super.loadAsset(url);\n }\n\n protected override async newBakeRenderer(): Promise<WebGPURenderer> {\n // A process with a document, such as a glts host's, has WebGPU of its own: bake on a canvas of that document, as a\n // .glts script does. A second WebGPU runtime beside the host's would take over globals the host's images upload with.\n if (typeof document !== \"undefined\") return createBakeRenderer();\n // Three's DOM canvas types exclude native canvases; its constructor checks the actual API.\n const renderer: unknown = Reflect.construct(WebGPURenderer, [{ canvas: await canvas(), antialias: false }]);\n if (!(renderer instanceof WebGPURenderer)) throw new Error(\"CachedLodLoader: three did not make a WebGPURenderer\");\n return setUpBakeRenderer(renderer);\n }\n\n protected override inputs(): Input[] {\n const state = sessions.getStore();\n if (!state) throw new Error(\"CachedLodLoader: a level was built outside loadAsync\");\n // three builds every level, whatever its source imports.\n const packages = [...new Set([\"three\", ...state.packages])].sort();\n return [...[...state.read].sort().map((path) => ({ path })), ...packages.map((name) => ({ package: name }))];\n }\n}\n\n/** A manager that serves root-relative paths from the public directory while a load runs. */\nfunction servingManager(): LoadingManager {\n const manager = new LoadingManager();\n manager.setURLModifier((url) => {\n if (!url.startsWith(\"/\") || url.startsWith(\"//\")) return url;\n if (!sessions.getStore()) throw new Error(`CachedLodLoader: cannot load \"${url}\" once the load that asked for it has ended`);\n return placeholderOrigin + url;\n });\n return manager;\n}\n\n/**\n * Loads `.glts` sources with a GLTSLoader made at the first load, resolving their packages as the app at `root` does,\n * and records the packages each imports.\n */\nclass ScriptLoader extends Loader<Object3D> {\n private loader: Promise<GLTSLoader> | undefined;\n\n constructor(\n manager: LoadingManager,\n private readonly root: string,\n ) {\n super(manager);\n }\n\n override async loadAsync(url: string): Promise<Object3D> {\n this.loader ??= import(\"@drawcall/glts\").then(\n ({ GLTSLoader }) => new GLTSLoader(this.manager, { resolve: (specifier) => resolveImport(specifier, this.root) }),\n );\n const scene = await (await this.loader).loadAsync(url);\n const { packages, runtimeModules } = scene.source;\n if (runtimeModules.length > 0)\n throw new Error(\n `CachedLodLoader: cannot precompute \"${url}\": it imports ${runtimeModules.join(\", \")} from a CDN at runtime, which a stored level cannot be checked against`,\n );\n const state = sessions.getStore();\n if (!state) throw new Error(`CachedLodLoader: \"${url}\" loaded outside loadAsync`);\n for (const name of packages) state.packages.add(name);\n return scene;\n }\n\n /** Free the GLTSLoader and the scenes it loaded, resolving once freed; the next load makes another. */\n async dispose(): Promise<void> {\n const loader = this.loader;\n this.loader = undefined;\n // A GLTSLoader that failed to load failed the load that made it.\n const made = await loader?.catch(() => undefined);\n made?.dispose();\n }\n}\n\nlet users = 0;\n/** What sessions install while any runs: the served fetch, and the canvas once one bakes. */\nlet installed: Promise<Install> | undefined;\n/**\n * The restore of the last sessions to finish, which the next install waits for: @drawcall/webgpu saves and restores\n * the globals it installs per canvas, so two canvases' lives must not overlap.\n */\nlet restored: Promise<void> = Promise.resolve();\nlet current: Install | undefined;\n\ninterface Install {\n /**\n * The canvas bakes draw on in a process without a document, made by the first source load or bake, so loads that only\n * read stored levels install no WebGPU runtime.\n */\n canvas?: Promise<Canvas>;\n restore: () => Promise<void>;\n}\n\n/** The canvas of the sessions running. */\nfunction canvas(): Promise<Canvas> {\n if (!current) throw new Error(\"CachedLodLoader: baking outside loadAsync\");\n return (current.canvas ??= createCanvas(1, 1));\n}\n\nasync function session<T>(state: Session, run: () => Promise<T>): Promise<T> {\n users++;\n // A failed restore failed the session that ran it. Sessions running together share one install.\n const shared = (installed ??= restored.catch(() => {}).then(install));\n try {\n current = await shared;\n return await sessions.run(state, run);\n } finally {\n if (--users === 0) {\n installed = current = undefined;\n // A failed install failed the run above.\n restored = shared.then(\n ({ restore }) => restore(),\n () => {},\n );\n await restored;\n }\n }\n}\n\n/**\n * The served fetch, and a canvas of @drawcall/webgpu once a session loads a source or bakes, which installs WebGPU,\n * image decoding and workers while it lives.\n */\nfunction install(): Install {\n const { fetch } = globalThis;\n globalThis.fetch = (input, init) => serve(fetch, input, init);\n const made: Install = {\n restore: async () => {\n globalThis.fetch = fetch;\n // A canvas that failed to make failed the bake that made it.\n const canvas = await made.canvas?.catch(() => undefined);\n await canvas?.dispose();\n },\n };\n return made;\n}\n\nasync function serve(fetch: typeof globalThis.fetch, input: RequestInfo | URL, init?: RequestInit): Promise<Response> {\n const url = new URL(input instanceof Request ? input.url : input);\n const state = sessions.getStore();\n if (!state || url.protocol === \"data:\" || url.protocol === \"blob:\") return fetch(input, init);\n if (url.origin !== placeholderOrigin)\n throw new Error(`CachedLodLoader: cannot precompute a load that fetches ${url.href}, which a stored level cannot be checked against`);\n const file = publicURL(url.pathname);\n try {\n const bytes = await readFile(fileURLToPath(file));\n state.read.add(file);\n return new Response(bytes);\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") return new Response(null, { status: 404 });\n throw error;\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drawcall/lod",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Level of detail for three.js: octahedral impostors, simplified and baked meshes, with dithered switching by on-screen size. WebGPURenderer only.",
|
|
6
6
|
"keywords": [
|