@openusd-wasm/pxr 0.0.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 KeJun <https://github.com/kejunmao>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # @openusd-wasm/pxr
2
+
3
+ Community ESM facade for OpenUSD `pxr` WebAssembly bindings.
4
+
5
+ This package is the high-level facade. The generated Emscripten module and Wasm
6
+ binary live in `@openusd-wasm/core`, matching the split used by projects such
7
+ as `ffmpeg.wasm`.
8
+
9
+ ```text
10
+ @openusd-wasm/pxr facade and TypeScript declarations
11
+ @openusd-wasm/core Emscripten core JavaScript and Wasm binary
12
+ ```
13
+
14
+ Use a statically imported core factory with explicit asset URLs:
15
+
16
+ ```ts
17
+ import createOpenUsdPxrWasm from '@openusd-wasm/core'
18
+ import { wasmURL, workerURL } from '@openusd-wasm/core/urls'
19
+ import { createPxr } from '@openusd-wasm/pxr'
20
+
21
+ const pxr = await createPxr({
22
+ core: createOpenUsdPxrWasm,
23
+ wasmURL,
24
+ workerURL,
25
+ })
26
+ ```
27
+
28
+ This form is recommended for bundlers such as Next.js/Turbopack because the
29
+ Emscripten core module is visible as a normal static import. For custom hosting
30
+ or CDN usage, you can still pass URLs manually:
31
+
32
+ ```ts
33
+ const pxr = await createPxr({
34
+ coreURL: 'https://cdn.example.com/openusd_pxr_wasm.js',
35
+ wasmURL: 'https://cdn.example.com/openusd_pxr_wasm.wasm',
36
+ })
37
+ ```
38
+
39
+ The returned namespace exposes `Gf`, `Sdf`, `Usd`, `UsdGeom`, `UsdPhysics`,
40
+ `UsdUtils`, and `FS` helpers for the virtual filesystem.
41
+
42
+ ## Unsupported APIs
43
+
44
+ The facade intentionally exposes a small JavaScript-friendly subset of `pxr`.
45
+ The following areas are not wrapped yet.
46
+
47
+ ### Gf
48
+
49
+ - Camera, Rotation, and non-4d matrix variants need value conversion coverage before exposing.
50
+ - Line, plane, frustum, interval, and dual quaternion helpers are deferred until their dependent value types are bound.
51
+
52
+ ### Sdf
53
+
54
+ - PrimSpec, AttributeSpec, and RelationshipSpec mutation proxies are deferred because list/proxy lifetimes need JS-safe wrappers.
55
+ - ChangeBlock, LayerOffset, Reference/Payload value classes, VariantSpec, and VariantSetSpec APIs are deferred to the next Sdf expansion.
56
+
57
+ ### Usd
58
+
59
+ - EditTarget/EditContext, StageCache, StagePopulationMask, StageLoadRules, VariantSets, Payloads, and PrimRange iterator objects are not wrapped yet.
60
+ - Generated Usd schema class coverage beyond concrete schema registration is deferred to schema-driven generation.
61
+
62
+ ### UsdGeom
63
+
64
+ - Generated schema classes beyond Xform, Sphere, Cube, and Mesh are deferred to schema-driven generation.
65
+ - PointInstancer, Camera, Imageable, BBoxCache overrides, and typed-array zero-copy bridges are deferred.
66
+
67
+ ### UsdPhysics
68
+
69
+ - Generated schema classes beyond CollisionAPI and RigidBodyAPI are deferred to schema-driven generation.
70
+ - Joints, limits, drives, parsing utilities, and metrics helpers are deferred to the next physics expansion.
71
+
72
+ ### UsdUtils
73
+
74
+ - StageCache, SparseValueWriter, Stitch, StitchClips, dependency extraction, FlattenLayerStack, TimeCodeRange, localization, and compliance helpers are deferred.
@@ -0,0 +1,190 @@
1
+ //#region src/bindings.d.ts
2
+ interface EmscriptenFs {
3
+ filesystems?: Record<string, unknown>;
4
+ mkdir(path: string): void;
5
+ mount(fsType: unknown, opts: Record<string, unknown>, mountPoint: string): void;
6
+ unmount(mountPoint: string): void;
7
+ writeFile(path: string, data: string | ArrayBuffer | ArrayBufferView): void;
8
+ readFile(path: string, opts?: unknown): unknown;
9
+ readdir(path: string): string[];
10
+ stat(path: string): {
11
+ mode: number;
12
+ size: number;
13
+ };
14
+ isDir(mode: number): boolean;
15
+ isFile(mode: number): boolean;
16
+ unlink(path: string): void;
17
+ rmdir(path: string): void;
18
+ rename(oldPath: string, newPath: string): void;
19
+ syncfs(populate: boolean, callback: (err?: unknown) => void): void;
20
+ }
21
+ interface WasmModule extends Record<string, unknown> {
22
+ FS?: EmscriptenFs;
23
+ mainScriptUrlOrBlob?: unknown;
24
+ PxrJsInitializeOpenUsdRuntime?: () => void;
25
+ }
26
+ interface PxrDisposable {
27
+ delete(): void;
28
+ using<T>(fn: (value: this) => T): T;
29
+ }
30
+ type PxrInstance = PxrDisposable & Record<string, any>;
31
+ type PxrClass = {
32
+ new (...args: any[]): PxrInstance;
33
+ [key: string]: any;
34
+ };
35
+ type PxrFunction = (...args: any[]) => any;
36
+ type PxrBindingObject = Record<string, any>;
37
+ type PxrNamespaceValue = PxrClass | PxrFunction | PxrBindingObject;
38
+ type PxrNamespace = Record<string, PxrNamespaceValue>;
39
+ type PxrModuleName = 'Gf' | 'Sdf' | 'Usd' | 'UsdGeom' | 'UsdPhysics' | 'UsdUtils';
40
+ //#endregion
41
+ //#region src/modules/gf.d.ts
42
+ interface PxrGfNamespace {
43
+ Vec2f: PxrClass;
44
+ Vec2d: PxrClass;
45
+ Vec2h: PxrClass;
46
+ Vec2i: PxrClass;
47
+ Vec3f: PxrClass;
48
+ Vec3d: PxrClass;
49
+ Vec3h: PxrClass;
50
+ Vec3i: PxrClass;
51
+ Vec4f: PxrClass;
52
+ Vec4d: PxrClass;
53
+ Vec4h: PxrClass;
54
+ Vec4i: PxrClass;
55
+ Matrix3d: PxrClass;
56
+ Matrix4d: PxrClass;
57
+ Quatf: PxrClass;
58
+ Quatd: PxrClass;
59
+ Quath: PxrClass;
60
+ Range1d: PxrClass;
61
+ Range2d: PxrClass;
62
+ Range3d: PxrClass;
63
+ Range3f: PxrClass;
64
+ BBox3d: PxrClass;
65
+ }
66
+ //#endregion
67
+ //#region src/modules/sdf.d.ts
68
+ interface PxrSdfNamespace {
69
+ Path: PxrClass;
70
+ AssetPath: PxrClass;
71
+ Layer: PxrClass;
72
+ PrimSpec: PxrClass;
73
+ ValueTypeName: PxrClass;
74
+ ValueTypeNames: PxrBindingObject;
75
+ }
76
+ //#endregion
77
+ //#region src/modules/usd.d.ts
78
+ interface PxrUsdNamespace {
79
+ Stage: PxrClass;
80
+ Prim: PxrClass;
81
+ Attribute: PxrClass;
82
+ Relationship: PxrClass;
83
+ References: PxrClass;
84
+ TimeCode: PxrClass;
85
+ }
86
+ //#endregion
87
+ //#region src/modules/usdGeom.d.ts
88
+ interface PxrUsdGeomNamespace {
89
+ Xform: PxrClass;
90
+ Sphere: PxrClass;
91
+ Cube: PxrClass;
92
+ Mesh: PxrClass;
93
+ Xformable: PxrClass;
94
+ XformOp: PxrClass;
95
+ Primvar: PxrClass;
96
+ PrimvarsAPI: PxrClass;
97
+ BBoxCache: PxrClass;
98
+ SetStageMetersPerUnit: PxrFunction;
99
+ SetStageUpAxis: PxrFunction;
100
+ GetStageUpAxis: PxrFunction;
101
+ Tokens: PxrBindingObject;
102
+ }
103
+ //#endregion
104
+ //#region src/modules/usdPhysics.d.ts
105
+ interface PxrUsdPhysicsNamespace {
106
+ CollisionAPI: PxrClass;
107
+ RigidBodyAPI: PxrClass;
108
+ }
109
+ //#endregion
110
+ //#region src/modules/usdUtils.d.ts
111
+ interface PxrUsdUtilsNamespace {
112
+ CreateNewUsdzPackage: PxrFunction;
113
+ }
114
+ //#endregion
115
+ //#region src/modules/index.d.ts
116
+ interface PxrModuleMap {
117
+ Gf: PxrGfNamespace;
118
+ Sdf: PxrSdfNamespace;
119
+ Usd: PxrUsdNamespace;
120
+ UsdGeom: PxrUsdGeomNamespace;
121
+ UsdPhysics: PxrUsdPhysicsNamespace;
122
+ UsdUtils: PxrUsdUtilsNamespace;
123
+ }
124
+ //#endregion
125
+ //#region src/index.d.ts
126
+ type WasmFactory = (options?: Record<string, unknown>) => Promise<WasmModule> | WasmModule;
127
+ type WasmFactoryModule = {
128
+ default?: WasmFactory;
129
+ createOpenUsdPxrWasm?: WasmFactory;
130
+ };
131
+ type PxrResourceURL = string | URL | Blob;
132
+ type PxrWasmFactory = WasmFactory;
133
+ type PxrWasmFactoryModule = WasmFactoryModule;
134
+ type PxrCoreFactory = WasmFactory | WasmFactoryModule;
135
+ interface PxrFsListEntry {
136
+ name: string;
137
+ path: string;
138
+ mode: number;
139
+ size: number;
140
+ isDir: boolean;
141
+ isFile: boolean;
142
+ }
143
+ interface PxrFsHelpers {
144
+ raw: EmscriptenFs;
145
+ mkdirp(path: string): void;
146
+ createDir(path: string): void;
147
+ deleteDir(path: string): void;
148
+ listDir(path: string): PxrFsListEntry[];
149
+ mount(mount: Record<string, unknown>): void;
150
+ mount(fsType: string, options: Record<string, unknown>, mountPoint: string): void;
151
+ unmount(mountPoint: string): void;
152
+ mountNodeFS(mountPoint: string, root?: string): void;
153
+ mountWorkerFS(mountPoint: string, options?: Record<string, unknown>): void;
154
+ mountIDBFS(mountPoint: string, options?: Record<string, unknown>): void;
155
+ writeFile(path: string, data: string | ArrayBuffer | ArrayBufferView): void;
156
+ readFile(path: string, encodingOrOpts?: 'binary' | 'utf8' | 'utf-8' | Record<string, unknown>): unknown;
157
+ exists(path: string): boolean;
158
+ deleteFile(path: string): void;
159
+ unlink(path: string): void;
160
+ rename(oldPath: string, newPath: string): void;
161
+ renameFile(oldPath: string, newPath: string): void;
162
+ syncfs(populate?: boolean): Promise<void>;
163
+ }
164
+ interface Pxr extends PxrModuleMap {
165
+ _module: WasmModule;
166
+ FS: PxrFsHelpers;
167
+ using<T extends PxrDisposable>(value: T): T;
168
+ }
169
+ interface CreatePxrOptions extends Record<string, unknown> {
170
+ core?: PxrCoreFactory;
171
+ coreURL?: PxrResourceURL;
172
+ wasmURL: PxrResourceURL;
173
+ workerURL?: PxrResourceURL;
174
+ mainScriptUrlOrBlob?: string | URL | Blob;
175
+ locateFile?: (path: string, prefix: string) => string;
176
+ mounts?: Array<Record<string, unknown>>;
177
+ files?: Record<string, string | ArrayBuffer | ArrayBufferView>;
178
+ preRun?: Function | Function[];
179
+ }
180
+ interface PxrCoreAssets {
181
+ core?: PxrCoreFactory;
182
+ coreURL?: PxrResourceURL;
183
+ wasmURL: PxrResourceURL;
184
+ workerURL?: PxrResourceURL;
185
+ }
186
+ type CreatePxrFromCoreOptions = Omit<CreatePxrOptions, 'core' | 'coreURL' | 'wasmURL' | 'workerURL'>;
187
+ declare function createPxr(options: CreatePxrOptions): Promise<Pxr>;
188
+ declare function createPxrFromCore(core: PxrCoreAssets, options?: CreatePxrFromCoreOptions): Promise<Pxr>;
189
+ //#endregion
190
+ export { CreatePxrFromCoreOptions, CreatePxrOptions, type EmscriptenFs, Pxr, type PxrBindingObject, type PxrClass, PxrCoreAssets, PxrCoreFactory, type PxrDisposable, PxrFsHelpers, PxrFsListEntry, type PxrFunction, type PxrGfNamespace, type PxrInstance, type PxrModuleMap, type PxrModuleName, type PxrNamespace, type PxrNamespaceValue, PxrResourceURL, type PxrSdfNamespace, type PxrUsdGeomNamespace, type PxrUsdNamespace, type PxrUsdPhysicsNamespace, type PxrUsdUtilsNamespace, PxrWasmFactory, PxrWasmFactoryModule, type WasmModule, createPxr, createPxr as default, createPxrFromCore };
@@ -0,0 +1,441 @@
1
+ //#region src/bindings.ts
2
+ function flatName(moduleName, name) {
3
+ return `PxrJs${moduleName}${name}`;
4
+ }
5
+ function attachUsing(value) {
6
+ if (!value) return value;
7
+ Object.defineProperty(value, "using", {
8
+ enumerable: false,
9
+ value(callback) {
10
+ try {
11
+ return callback(value);
12
+ } finally {
13
+ if (value && value.delete) value.delete();
14
+ }
15
+ }
16
+ });
17
+ return value;
18
+ }
19
+ function installUsing(cls) {
20
+ if (!cls || !cls.prototype || cls.prototype.using) return cls;
21
+ try {
22
+ Object.defineProperty(cls.prototype, "using", {
23
+ enumerable: false,
24
+ value(callback) {
25
+ try {
26
+ return callback(this);
27
+ } finally {
28
+ if (this && this.delete) this.delete();
29
+ }
30
+ }
31
+ });
32
+ } catch {}
33
+ return cls;
34
+ }
35
+ function mapClass(module, embindName) {
36
+ const cls = module[embindName];
37
+ if (typeof cls !== "function") throw new Error(`Missing Embind export ${embindName}`);
38
+ return installUsing(cls);
39
+ }
40
+ function mapFunction(module, embindName) {
41
+ const fn = module[embindName];
42
+ if (typeof fn !== "function") throw new Error(`Missing Embind export ${embindName}`);
43
+ return (...args) => fn(...args);
44
+ }
45
+ function mapObject(module, embindName) {
46
+ const fn = module[embindName];
47
+ if (typeof fn !== "function") throw new Error(`Missing Embind export ${embindName}`);
48
+ return fn();
49
+ }
50
+ function bindClass(module, moduleName, name) {
51
+ return mapClass(module, flatName(moduleName, name));
52
+ }
53
+ function bindFunction(module, moduleName, name) {
54
+ return mapFunction(module, flatName(moduleName, name));
55
+ }
56
+ function bindObject(module, moduleName, name) {
57
+ return mapObject(module, flatName(moduleName, name));
58
+ }
59
+ //#endregion
60
+ //#region src/modules/gf.ts
61
+ function buildGfNamespace(module) {
62
+ return {
63
+ Vec2f: bindClass(module, "Gf", "Vec2f"),
64
+ Vec2d: bindClass(module, "Gf", "Vec2d"),
65
+ Vec2h: bindClass(module, "Gf", "Vec2h"),
66
+ Vec2i: bindClass(module, "Gf", "Vec2i"),
67
+ Vec3f: bindClass(module, "Gf", "Vec3f"),
68
+ Vec3d: bindClass(module, "Gf", "Vec3d"),
69
+ Vec3h: bindClass(module, "Gf", "Vec3h"),
70
+ Vec3i: bindClass(module, "Gf", "Vec3i"),
71
+ Vec4f: bindClass(module, "Gf", "Vec4f"),
72
+ Vec4d: bindClass(module, "Gf", "Vec4d"),
73
+ Vec4h: bindClass(module, "Gf", "Vec4h"),
74
+ Vec4i: bindClass(module, "Gf", "Vec4i"),
75
+ Matrix3d: bindClass(module, "Gf", "Matrix3d"),
76
+ Matrix4d: bindClass(module, "Gf", "Matrix4d"),
77
+ Quatf: bindClass(module, "Gf", "Quatf"),
78
+ Quatd: bindClass(module, "Gf", "Quatd"),
79
+ Quath: bindClass(module, "Gf", "Quath"),
80
+ Range1d: bindClass(module, "Gf", "Range1d"),
81
+ Range2d: bindClass(module, "Gf", "Range2d"),
82
+ Range3d: bindClass(module, "Gf", "Range3d"),
83
+ Range3f: bindClass(module, "Gf", "Range3f"),
84
+ BBox3d: bindClass(module, "Gf", "BBox3d")
85
+ };
86
+ }
87
+ //#endregion
88
+ //#region src/modules/sdf.ts
89
+ function buildSdfNamespace(module) {
90
+ return {
91
+ Path: bindClass(module, "Sdf", "Path"),
92
+ AssetPath: bindClass(module, "Sdf", "AssetPath"),
93
+ Layer: bindClass(module, "Sdf", "Layer"),
94
+ PrimSpec: bindClass(module, "Sdf", "PrimSpec"),
95
+ ValueTypeName: bindClass(module, "Sdf", "ValueTypeName"),
96
+ ValueTypeNames: bindObject(module, "Sdf", "ValueTypeNames")
97
+ };
98
+ }
99
+ //#endregion
100
+ //#region src/modules/usd.ts
101
+ function buildUsdNamespace(module) {
102
+ return {
103
+ Stage: bindClass(module, "Usd", "Stage"),
104
+ Prim: bindClass(module, "Usd", "Prim"),
105
+ Attribute: bindClass(module, "Usd", "Attribute"),
106
+ Relationship: bindClass(module, "Usd", "Relationship"),
107
+ References: bindClass(module, "Usd", "References"),
108
+ TimeCode: bindClass(module, "Usd", "TimeCode")
109
+ };
110
+ }
111
+ //#endregion
112
+ //#region src/modules/usdGeom.ts
113
+ function buildUsdGeomNamespace(module) {
114
+ return {
115
+ Xform: bindClass(module, "UsdGeom", "Xform"),
116
+ Sphere: bindClass(module, "UsdGeom", "Sphere"),
117
+ Cube: bindClass(module, "UsdGeom", "Cube"),
118
+ Mesh: bindClass(module, "UsdGeom", "Mesh"),
119
+ Xformable: bindClass(module, "UsdGeom", "Xformable"),
120
+ XformOp: bindClass(module, "UsdGeom", "XformOp"),
121
+ Primvar: bindClass(module, "UsdGeom", "Primvar"),
122
+ PrimvarsAPI: bindClass(module, "UsdGeom", "PrimvarsAPI"),
123
+ BBoxCache: bindClass(module, "UsdGeom", "BBoxCache"),
124
+ SetStageMetersPerUnit: bindFunction(module, "UsdGeom", "SetStageMetersPerUnit"),
125
+ SetStageUpAxis: bindFunction(module, "UsdGeom", "SetStageUpAxis"),
126
+ GetStageUpAxis: bindFunction(module, "UsdGeom", "GetStageUpAxis"),
127
+ Tokens: bindObject(module, "UsdGeom", "Tokens")
128
+ };
129
+ }
130
+ //#endregion
131
+ //#region src/modules/usdPhysics.ts
132
+ function buildUsdPhysicsNamespace(module) {
133
+ return {
134
+ CollisionAPI: bindClass(module, "UsdPhysics", "CollisionAPI"),
135
+ RigidBodyAPI: bindClass(module, "UsdPhysics", "RigidBodyAPI")
136
+ };
137
+ }
138
+ //#endregion
139
+ //#region src/modules/usdUtils.ts
140
+ function buildUsdUtilsNamespace(module) {
141
+ return { CreateNewUsdzPackage: bindFunction(module, "UsdUtils", "CreateNewUsdzPackage") };
142
+ }
143
+ //#endregion
144
+ //#region src/modules/index.ts
145
+ function buildPxrModules(module) {
146
+ return {
147
+ Gf: buildGfNamespace(module),
148
+ Sdf: buildSdfNamespace(module),
149
+ Usd: buildUsdNamespace(module),
150
+ UsdGeom: buildUsdGeomNamespace(module),
151
+ UsdPhysics: buildUsdPhysicsNamespace(module),
152
+ UsdUtils: buildUsdUtilsNamespace(module)
153
+ };
154
+ }
155
+ //#endregion
156
+ //#region src/modules/sdfConvenience.ts
157
+ function installGetter(cls, name, getter) {
158
+ if (!cls?.prototype) return;
159
+ if (Object.getOwnPropertyDescriptor(cls.prototype, name)) return;
160
+ try {
161
+ Object.defineProperty(cls.prototype, name, {
162
+ enumerable: false,
163
+ get() {
164
+ return getter(this);
165
+ }
166
+ });
167
+ } catch {}
168
+ }
169
+ function installAccessor(cls, name, getter, setter) {
170
+ if (!cls?.prototype) return;
171
+ if (Object.getOwnPropertyDescriptor(cls.prototype, name)) return;
172
+ try {
173
+ Object.defineProperty(cls.prototype, name, {
174
+ enumerable: false,
175
+ get() {
176
+ return getter(this);
177
+ },
178
+ set(next) {
179
+ setter(this, next);
180
+ }
181
+ });
182
+ } catch {}
183
+ }
184
+ function installSdfConvenienceAccessors(pxr) {
185
+ installGetter(pxr.Sdf.AssetPath, "path", (value) => value.GetAssetPath());
186
+ installGetter(pxr.Sdf.AssetPath, "resolvedPath", (value) => value.GetResolvedPath());
187
+ installAccessor(pxr.Sdf.Layer, "subLayerPaths", (value) => value.GetSubLayerPaths(), (value, next) => value.SetSubLayerPaths(next));
188
+ }
189
+ //#endregion
190
+ //#region src/index.ts
191
+ function mkdirp(FS, path) {
192
+ const parts = path.split("/").filter(Boolean);
193
+ let current = path.startsWith("/") ? "/" : "";
194
+ for (const part of parts) {
195
+ current = current === "/" ? `/${part}` : `${current}/${part}`;
196
+ try {
197
+ FS.mkdir(current);
198
+ } catch (err) {
199
+ try {
200
+ if (FS.isDir(FS.stat(current).mode)) continue;
201
+ } catch {}
202
+ throw err;
203
+ }
204
+ }
205
+ }
206
+ function parentPath(path) {
207
+ const parts = path.split("/");
208
+ parts.pop();
209
+ const parent = parts.join("/");
210
+ if (parent) return parent;
211
+ return path.startsWith("/") ? "/" : ".";
212
+ }
213
+ function joinFsPath(base, name) {
214
+ if (base === "/") return `/${name}`;
215
+ return `${base.replace(/\/+$/, "")}/${name}`;
216
+ }
217
+ function ensureParent(FS, path) {
218
+ const parent = parentPath(path);
219
+ if (parent !== ".") mkdirp(FS, parent);
220
+ }
221
+ function isNodeLike() {
222
+ const processLike = globalThis.process;
223
+ return !!processLike?.versions?.node && processLike.type !== "renderer";
224
+ }
225
+ function isBlobLike(value) {
226
+ return typeof Blob !== "undefined" && value instanceof Blob;
227
+ }
228
+ function toUrlString(value, baseUrl = import.meta.url) {
229
+ if (value === void 0 || value === null) return void 0;
230
+ if (isBlobLike(value)) return URL.createObjectURL(value);
231
+ if (value instanceof URL) return value.href;
232
+ if (typeof value !== "string") return value;
233
+ try {
234
+ return new URL(value, baseUrl).href;
235
+ } catch {
236
+ return value;
237
+ }
238
+ }
239
+ function requireUrlString(value, name) {
240
+ if (value === void 0 || value === null) throw new TypeError(`${name} is required`);
241
+ const url = toUrlString(value);
242
+ if (typeof url !== "string") throw new TypeError(`${name} must resolve to a string URL`);
243
+ return url;
244
+ }
245
+ function fileUrlToPathString(value) {
246
+ const url = value instanceof URL ? value : new URL(value);
247
+ if (url.protocol !== "file:") return value instanceof URL ? url.href : value;
248
+ return decodeURIComponent(url.pathname);
249
+ }
250
+ function toWorkerScript(value) {
251
+ if (value === void 0 || value === null || isBlobLike(value)) return value;
252
+ if (isNodeLike()) {
253
+ if (value instanceof URL) return fileUrlToPathString(value);
254
+ if (typeof value === "string" && value.startsWith("file:")) return fileUrlToPathString(value);
255
+ return value;
256
+ }
257
+ return toUrlString(value);
258
+ }
259
+ function resolveWasmFactory(core, source = "core") {
260
+ const factory = typeof core === "function" ? core : core.default ?? core.createOpenUsdPxrWasm;
261
+ if (typeof factory !== "function") throw new Error(`Unable to load OpenUSD Wasm factory from ${source}`);
262
+ return factory;
263
+ }
264
+ function runtimeImport(url) {
265
+ return Function("url", "return import(url)")(url);
266
+ }
267
+ async function loadWasmFactory(core, coreURL) {
268
+ if (core !== void 0) return resolveWasmFactory(core);
269
+ const url = requireUrlString(coreURL, "coreURL");
270
+ return resolveWasmFactory(await runtimeImport(url), url);
271
+ }
272
+ function buildLocateFile({ wasmURL, workerURL, locateFile }) {
273
+ const resolvedWasmURL = requireUrlString(wasmURL, "wasmURL");
274
+ const resolvedWorkerURL = workerURL === void 0 ? void 0 : requireUrlString(workerURL, "workerURL");
275
+ return (path, prefix) => {
276
+ if (path.endsWith(".wasm")) return resolvedWasmURL;
277
+ if (resolvedWorkerURL && (path.endsWith(".worker.js") || path.endsWith(".worker.mjs"))) return String(resolvedWorkerURL);
278
+ if (locateFile) return locateFile(path, prefix);
279
+ return `${prefix || ""}${path}`;
280
+ };
281
+ }
282
+ function requireFs(module) {
283
+ if (!module.FS) throw new Error("openusd_pxr_wasm was built without FS export");
284
+ return module.FS;
285
+ }
286
+ function normalizeMountArgs(mountOrType, options = {}, mountPoint) {
287
+ if (typeof mountOrType === "string") return {
288
+ type: mountOrType,
289
+ ...options || {},
290
+ mountPoint
291
+ };
292
+ return mountOrType || {};
293
+ }
294
+ function mountFilesystem(module, mountOrType, options, mountPointArg) {
295
+ const FS = requireFs(module);
296
+ const mount = normalizeMountArgs(mountOrType, options, mountPointArg);
297
+ const type = typeof mount.type === "string" ? mount.type : "MEMFS";
298
+ const mountPoint = typeof mount.mountPoint === "string" ? mount.mountPoint : typeof mount.path === "string" ? mount.path : void 0;
299
+ if (!mountPoint) throw new Error("mountPoint is required");
300
+ mkdirp(FS, mountPoint);
301
+ if (type === "MEMFS") return;
302
+ const fsType = FS.filesystems?.[type];
303
+ if (!fsType) throw new Error(`${type} is not available in this Wasm build`);
304
+ const opts = { ...mount };
305
+ delete opts.type;
306
+ delete opts.mountPoint;
307
+ delete opts.path;
308
+ FS.mount(fsType, opts, mountPoint);
309
+ }
310
+ function installFiles(module, files) {
311
+ if (!files) return;
312
+ const FS = requireFs(module);
313
+ for (const [path, data] of Object.entries(files)) {
314
+ ensureParent(FS, path);
315
+ FS.writeFile(path, data);
316
+ }
317
+ }
318
+ function normalizeCallbacks(callbacks) {
319
+ if (!callbacks) return [];
320
+ return Array.isArray(callbacks) ? callbacks : [callbacks];
321
+ }
322
+ function readFile(FS, path, encodingOrOpts) {
323
+ if (typeof encodingOrOpts === "string") {
324
+ if (encodingOrOpts === "utf8" || encodingOrOpts === "utf-8") return FS.readFile(path, { encoding: "utf8" });
325
+ return FS.readFile(path);
326
+ }
327
+ return FS.readFile(path, encodingOrOpts);
328
+ }
329
+ function listDir(FS, path) {
330
+ return FS.readdir(path).filter((name) => name !== "." && name !== "..").map((name) => {
331
+ const childPath = joinFsPath(path, name);
332
+ const stat = FS.stat(childPath);
333
+ return {
334
+ name,
335
+ path: childPath,
336
+ mode: stat.mode,
337
+ size: stat.size,
338
+ isDir: FS.isDir(stat.mode),
339
+ isFile: FS.isFile(stat.mode)
340
+ };
341
+ });
342
+ }
343
+ function defaultNodeRoot() {
344
+ if (!globalThis.process?.cwd) throw new Error("A NODEFS root is required outside Node.js");
345
+ return globalThis.process.cwd();
346
+ }
347
+ function buildFsHelpers(module) {
348
+ const FS = requireFs(module);
349
+ const rename = (oldPath, newPath) => {
350
+ ensureParent(FS, newPath);
351
+ FS.rename(oldPath, newPath);
352
+ };
353
+ return {
354
+ raw: FS,
355
+ mkdirp: (path) => mkdirp(FS, path),
356
+ createDir: (path) => mkdirp(FS, path),
357
+ deleteDir: (path) => FS.rmdir(path),
358
+ listDir: (path) => listDir(FS, path),
359
+ mount: (mountOrType, options, mountPoint) => mountFilesystem(module, mountOrType, options, mountPoint),
360
+ unmount: (mountPoint) => FS.unmount(mountPoint),
361
+ mountNodeFS: (mountPoint, root = defaultNodeRoot()) => mountFilesystem(module, {
362
+ type: "NODEFS",
363
+ mountPoint,
364
+ root
365
+ }),
366
+ mountWorkerFS: (mountPoint, options = {}) => mountFilesystem(module, {
367
+ type: "WORKERFS",
368
+ mountPoint,
369
+ ...options
370
+ }),
371
+ mountIDBFS: (mountPoint, options = {}) => mountFilesystem(module, {
372
+ type: "IDBFS",
373
+ mountPoint,
374
+ ...options
375
+ }),
376
+ writeFile: (path, data) => {
377
+ ensureParent(FS, path);
378
+ FS.writeFile(path, data);
379
+ },
380
+ readFile: (path, encodingOrOpts) => readFile(FS, path, encodingOrOpts),
381
+ exists: (path) => {
382
+ try {
383
+ FS.stat(path);
384
+ return true;
385
+ } catch {
386
+ return false;
387
+ }
388
+ },
389
+ deleteFile: (path) => FS.unlink(path),
390
+ unlink: (path) => FS.unlink(path),
391
+ rename,
392
+ renameFile: rename,
393
+ syncfs: (populate = false) => new Promise((resolve, reject) => {
394
+ FS.syncfs(populate, (err) => err ? reject(err) : resolve());
395
+ })
396
+ };
397
+ }
398
+ function buildPxr(module) {
399
+ const pxr = {
400
+ _module: module,
401
+ FS: buildFsHelpers(module),
402
+ using: attachUsing,
403
+ ...buildPxrModules(module)
404
+ };
405
+ installSdfConvenienceAccessors(pxr);
406
+ return pxr;
407
+ }
408
+ function initializeOpenUsdRuntime(module) {
409
+ if (typeof module.PxrJsInitializeOpenUsdRuntime !== "function") throw new Error("openusd_pxr_wasm was built without OpenUSD runtime initialization support");
410
+ module.PxrJsInitializeOpenUsdRuntime();
411
+ }
412
+ async function createPxr(options) {
413
+ if (!options) throw new TypeError("createPxr requires options with core or coreURL and wasmURL");
414
+ const { core, coreURL, wasmURL, workerURL, mainScriptUrlOrBlob, mounts = [], files, preRun, locateFile, ...wasmOptions } = options;
415
+ wasmOptions.locateFile = buildLocateFile({
416
+ wasmURL,
417
+ workerURL,
418
+ locateFile
419
+ });
420
+ wasmOptions.preRun = [...normalizeCallbacks(preRun), (module) => {
421
+ for (const mount of mounts) mountFilesystem(module, mount);
422
+ installFiles(module, files);
423
+ }];
424
+ if (mainScriptUrlOrBlob !== void 0) wasmOptions.mainScriptUrlOrBlob = toWorkerScript(mainScriptUrlOrBlob);
425
+ else if (workerURL !== void 0) wasmOptions.mainScriptUrlOrBlob = toWorkerScript(workerURL);
426
+ const module = await (await loadWasmFactory(core, coreURL))(wasmOptions);
427
+ initializeOpenUsdRuntime(module);
428
+ return buildPxr(module);
429
+ }
430
+ async function createPxrFromCore(core, options = {}) {
431
+ if (!core) throw new TypeError("createPxrFromCore requires @openusd-wasm/core assets");
432
+ return createPxr({
433
+ ...options,
434
+ core: core.core,
435
+ coreURL: core.coreURL,
436
+ wasmURL: core.wasmURL,
437
+ workerURL: core.workerURL ?? core.coreURL
438
+ });
439
+ }
440
+ //#endregion
441
+ export { createPxr, createPxr as default, createPxrFromCore };
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@openusd-wasm/pxr",
3
+ "type": "module",
4
+ "version": "0.0.1",
5
+ "description": "Community TypeScript facade for OpenUSD pxr WebAssembly bindings.",
6
+ "license": "MIT",
7
+ "homepage": "https://github.com/openusd-wasm/openusd-pxr-wasm",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/openusd-wasm/openusd-pxr-wasm.git",
11
+ "directory": "packages/pxr"
12
+ },
13
+ "main": "./dist/openusd_pxr.js",
14
+ "module": "./dist/openusd_pxr.js",
15
+ "types": "./dist/openusd_pxr.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/openusd_pxr.d.ts",
19
+ "import": "./dist/openusd_pxr.js"
20
+ },
21
+ "./package.json": "./package.json"
22
+ },
23
+ "files": [
24
+ "dist"
25
+ ],
26
+ "devDependencies": {
27
+ "@types/node": "^25.6.2",
28
+ "@typescript/native-preview": "7.0.0-dev.20260509.2",
29
+ "tsdown": "^0.22.0",
30
+ "typescript": "^6.0.3",
31
+ "vitest": "^4.1.5"
32
+ },
33
+ "scripts": {
34
+ "build": "tsdown",
35
+ "dev": "tsdown --watch",
36
+ "debug": "tsdown --sourcemap",
37
+ "test": "vitest run",
38
+ "typecheck": "tsc --noEmit"
39
+ }
40
+ }