@zephyr3d/editor 0.3.4 → 0.3.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.
Files changed (64) hide show
  1. package/dist/assets/{index-DzQzWsCG.js → index-DlnbO59X.js} +2 -2
  2. package/dist/assistant/zephyr-types-index.json +9 -10
  3. package/dist/index.html +1 -1
  4. package/dist/modules/zephyr3d_backend-webgpu.js +13 -12
  5. package/dist/modules/zephyr3d_backend-webgpu.js.map +1 -1
  6. package/dist/modules/zephyr3d_base.js +152 -152
  7. package/dist/modules/zephyr3d_base.js.map +1 -1
  8. package/dist/modules/zephyr3d_device.js +15 -15
  9. package/dist/modules/zephyr3d_device.js.map +1 -1
  10. package/dist/modules/zephyr3d_loaders.js +6 -6
  11. package/dist/modules/zephyr3d_loaders.js.map +1 -1
  12. package/dist/modules/zephyr3d_scene.js +1382 -1385
  13. package/dist/modules/zephyr3d_scene.js.map +1 -1
  14. package/dist/vendor/zephyr3d/backend-webgpu/dist/capabilities_webgpu.js +7 -6
  15. package/dist/vendor/zephyr3d/backend-webgpu/dist/capabilities_webgpu.js.map +1 -1
  16. package/dist/vendor/zephyr3d/backend-webgpu/dist/renderpass_webgpu.js +6 -6
  17. package/dist/vendor/zephyr3d/backend-webgpu/dist/renderpass_webgpu.js.map +1 -1
  18. package/dist/vendor/zephyr3d/base/dist/vfs/common.js +152 -152
  19. package/dist/vendor/zephyr3d/base/dist/vfs/common.js.map +1 -1
  20. package/dist/vendor/zephyr3d/device/dist/device.js +15 -15
  21. package/dist/vendor/zephyr3d/device/dist/device.js.map +1 -1
  22. package/dist/vendor/zephyr3d/loaders/dist/gltf/gltf_importer.js +6 -6
  23. package/dist/vendor/zephyr3d/loaders/dist/gltf/gltf_importer.js.map +1 -1
  24. package/dist/vendor/zephyr3d/scene/dist/animation/animationset.js +191 -194
  25. package/dist/vendor/zephyr3d/scene/dist/animation/animationset.js.map +1 -1
  26. package/dist/vendor/zephyr3d/scene/dist/animation/joint_dynamics_modifier.js +19 -19
  27. package/dist/vendor/zephyr3d/scene/dist/animation/joint_dynamics_modifier.js.map +1 -1
  28. package/dist/vendor/zephyr3d/scene/dist/app/engine.js +131 -131
  29. package/dist/vendor/zephyr3d/scene/dist/app/engine.js.map +1 -1
  30. package/dist/vendor/zephyr3d/scene/dist/app/scriptregistry.js +119 -119
  31. package/dist/vendor/zephyr3d/scene/dist/app/scriptregistry.js.map +1 -1
  32. package/dist/vendor/zephyr3d/scene/dist/asset/model.js +62 -62
  33. package/dist/vendor/zephyr3d/scene/dist/asset/model.js.map +1 -1
  34. package/dist/vendor/zephyr3d/scene/dist/avatar/wardrobe.js +13 -13
  35. package/dist/vendor/zephyr3d/scene/dist/avatar/wardrobe.js.map +1 -1
  36. package/dist/vendor/zephyr3d/scene/dist/camera/camera.js +201 -201
  37. package/dist/vendor/zephyr3d/scene/dist/camera/camera.js.map +1 -1
  38. package/dist/vendor/zephyr3d/scene/dist/index.d.ts +1 -1
  39. package/dist/vendor/zephyr3d/scene/dist/material/mixins/lightmodel/pbrmetallicroughness.js +5 -5
  40. package/dist/vendor/zephyr3d/scene/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
  41. package/dist/vendor/zephyr3d/scene/dist/material/mtoon.js +4 -4
  42. package/dist/vendor/zephyr3d/scene/dist/material/mtoon.js.map +1 -1
  43. package/dist/vendor/zephyr3d/scene/dist/material/pbrblueprint.js +11 -11
  44. package/dist/vendor/zephyr3d/scene/dist/material/pbrblueprint.js.map +1 -1
  45. package/dist/vendor/zephyr3d/scene/dist/material/shader/helper.js +284 -284
  46. package/dist/vendor/zephyr3d/scene/dist/material/shader/helper.js.map +1 -1
  47. package/dist/vendor/zephyr3d/scene/dist/posteffect/ssr.js +9 -9
  48. package/dist/vendor/zephyr3d/scene/dist/posteffect/ssr.js.map +1 -1
  49. package/dist/vendor/zephyr3d/scene/dist/render/lightpass.js +5 -5
  50. package/dist/vendor/zephyr3d/scene/dist/render/lightpass.js.map +1 -1
  51. package/dist/vendor/zephyr3d/scene/dist/render/renderer.js +7 -7
  52. package/dist/vendor/zephyr3d/scene/dist/render/renderer.js.map +1 -1
  53. package/dist/vendor/zephyr3d/scene/dist/shadow/esm.js +1 -1
  54. package/dist/vendor/zephyr3d/scene/dist/shadow/esm.js.map +1 -1
  55. package/dist/vendor/zephyr3d/scene/dist/shadow/shadow_region.js +45 -45
  56. package/dist/vendor/zephyr3d/scene/dist/shadow/shadow_region.js.map +1 -1
  57. package/dist/vendor/zephyr3d/scene/dist/utility/serialization/manager.js +275 -275
  58. package/dist/vendor/zephyr3d/scene/dist/utility/serialization/manager.js.map +1 -1
  59. package/dist/vendor/zephyr3d/scene/dist/utility/serialization/scene/camera.js.map +1 -1
  60. package/dist/vendor/zephyr3d/scene/dist/utility/serialization/scene/mesh.js.map +1 -1
  61. package/dist/vendor/zephyr3d/scene/dist/utility/serialization/scene/sprite.js.map +1 -1
  62. package/package.json +3 -3
  63. package/dist/vendor/zephyr3d/scene/dist/animation/joint_dynamics/convex_collider.js +0 -320
  64. package/dist/vendor/zephyr3d/scene/dist/animation/joint_dynamics/convex_collider.js.map +0 -1
@@ -41,35 +41,35 @@ const mimeTypes = {
41
41
  '.zprefab': 'application/vnd.zephyr3d.prefab+json',
42
42
  '.zabc': 'application/vnd.zephyr3d.alembic-cache+json'
43
43
  };
44
- /**
45
- * Path utilities.
46
- *
47
- * Provides POSIX-like path manipulation helpers (pure string operations),
48
- * including normalization, joining, dirname/basename/extname extraction,
49
- * absolute-path detection, and relative path computation.
50
- *
51
- * Notes:
52
- * - Uses "/" as the separator (web/URL or POSIX-like paths).
53
- * - All methods are pure and do not touch a real filesystem.
54
- * - `normalize` collapses ".", "..", and redundant slashes.
55
- *
56
- * @public
44
+ /**
45
+ * Path utilities.
46
+ *
47
+ * Provides POSIX-like path manipulation helpers (pure string operations),
48
+ * including normalization, joining, dirname/basename/extname extraction,
49
+ * absolute-path detection, and relative path computation.
50
+ *
51
+ * Notes:
52
+ * - Uses "/" as the separator (web/URL or POSIX-like paths).
53
+ * - All methods are pure and do not touch a real filesystem.
54
+ * - `normalize` collapses ".", "..", and redundant slashes.
55
+ *
56
+ * @public
57
57
  */ class PathUtils {
58
- /**
59
- * Normalizes a path by collapsing redundant slashes, removing "." segments,
60
- * and resolving ".." segments.
61
- *
62
- * Rules:
63
- * - Multiple consecutive "/" are collapsed into a single "/".
64
- * - "." segments are removed.
65
- * - ".." removes the previous segment (no-op at root).
66
- * - The result always starts with "/" (absolute form).
67
- *
68
- * Example:
69
- * - normalize('/a//b/./c/../d') -\> '/a/b/d'
70
- *
71
- * @param path - Input path (relative or absolute).
72
- * @returns The normalized absolute path (always starting with "/").
58
+ /**
59
+ * Normalizes a path by collapsing redundant slashes, removing "." segments,
60
+ * and resolving ".." segments.
61
+ *
62
+ * Rules:
63
+ * - Multiple consecutive "/" are collapsed into a single "/".
64
+ * - "." segments are removed.
65
+ * - ".." removes the previous segment (no-op at root).
66
+ * - The result always starts with "/" (absolute form).
67
+ *
68
+ * Example:
69
+ * - normalize('/a//b/./c/../d') -\> '/a/b/d'
70
+ *
71
+ * @param path - Input path (relative or absolute).
72
+ * @returns The normalized absolute path (always starting with "/").
73
73
  */ static normalize(path) {
74
74
  const parts = path.split('/').filter((p)=>p && p !== '.');
75
75
  const result = [];
@@ -82,55 +82,55 @@ const mimeTypes = {
82
82
  }
83
83
  return '/' + result.join('/');
84
84
  }
85
- /**
86
- * Joins multiple path segments and normalizes the result.
87
- *
88
- * Behavior:
89
- * - Concatenates segments with "/" and then runs `normalize`.
90
- * - The returned path is always absolute.
91
- *
92
- * Example:
93
- * - join('/a', 'b', '../c') -\> '/a/c'
94
- *
95
- * @param paths - Path segments in order.
96
- * @returns Normalized absolute path.
85
+ /**
86
+ * Joins multiple path segments and normalizes the result.
87
+ *
88
+ * Behavior:
89
+ * - Concatenates segments with "/" and then runs `normalize`.
90
+ * - The returned path is always absolute.
91
+ *
92
+ * Example:
93
+ * - join('/a', 'b', '../c') -\> '/a/c'
94
+ *
95
+ * @param paths - Path segments in order.
96
+ * @returns Normalized absolute path.
97
97
  */ static join(...paths) {
98
98
  return this.normalize(paths.join('/'));
99
99
  }
100
- /**
101
- * Returns the directory name (parent directory) of a path.
102
- *
103
- * Behavior:
104
- * - Applies `normalize` first.
105
- * - If the path is root "/" or has no parent, returns "/".
106
- *
107
- * Examples:
108
- * - dirname('/a/b/c') -\> '/a/b'
109
- * - dirname('/a') -\> '/'
110
- * - dirname('/') -\> '/'
111
- *
112
- * @param path - Input path.
113
- * @returns Directory path of the input.
100
+ /**
101
+ * Returns the directory name (parent directory) of a path.
102
+ *
103
+ * Behavior:
104
+ * - Applies `normalize` first.
105
+ * - If the path is root "/" or has no parent, returns "/".
106
+ *
107
+ * Examples:
108
+ * - dirname('/a/b/c') -\> '/a/b'
109
+ * - dirname('/a') -\> '/'
110
+ * - dirname('/') -\> '/'
111
+ *
112
+ * @param path - Input path.
113
+ * @returns Directory path of the input.
114
114
  */ static dirname(path) {
115
115
  const normalized = this.normalize(path);
116
116
  const lastSlash = normalized.lastIndexOf('/');
117
117
  return lastSlash <= 0 ? '/' : normalized.slice(0, lastSlash);
118
118
  }
119
- /**
120
- * Returns the last portion of a path (file name).
121
- *
122
- * Behavior:
123
- * - Applies `normalize` first.
124
- * - If `ext` is provided and the name ends with it, the extension is stripped.
125
- *
126
- * Examples:
127
- * - basename('/a/b/c.txt') -\> 'c.txt'
128
- * - basename('/a/b/c.txt', '.txt') -\> 'c'
129
- * - basename('/') -\> ''
130
- *
131
- * @param path - Input path.
132
- * @param ext - Optional extension to strip (exact suffix match).
133
- * @returns The base name of the path.
119
+ /**
120
+ * Returns the last portion of a path (file name).
121
+ *
122
+ * Behavior:
123
+ * - Applies `normalize` first.
124
+ * - If `ext` is provided and the name ends with it, the extension is stripped.
125
+ *
126
+ * Examples:
127
+ * - basename('/a/b/c.txt') -\> 'c.txt'
128
+ * - basename('/a/b/c.txt', '.txt') -\> 'c'
129
+ * - basename('/') -\> ''
130
+ *
131
+ * @param path - Input path.
132
+ * @param ext - Optional extension to strip (exact suffix match).
133
+ * @returns The base name of the path.
134
134
  */ static basename(path, ext) {
135
135
  const normalized = this.normalize(path);
136
136
  const lastSlash = normalized.lastIndexOf('/');
@@ -140,44 +140,44 @@ const mimeTypes = {
140
140
  }
141
141
  return name;
142
142
  }
143
- /**
144
- * Returns the extension of the path, including the leading dot.
145
- *
146
- * Behavior:
147
- * - Based on the result of `basename`.
148
- * - If there is no dot, returns an empty string.
149
- *
150
- * Examples:
151
- * - extname('/a/b/c.txt') -\> '.txt'
152
- * - extname('/a/b/c') -\> ''
153
- *
154
- * @param path - Input path.
155
- * @returns The extension (e.g., ".txt") or an empty string if none.
143
+ /**
144
+ * Returns the extension of the path, including the leading dot.
145
+ *
146
+ * Behavior:
147
+ * - Based on the result of `basename`.
148
+ * - If there is no dot, returns an empty string.
149
+ *
150
+ * Examples:
151
+ * - extname('/a/b/c.txt') -\> '.txt'
152
+ * - extname('/a/b/c') -\> ''
153
+ *
154
+ * @param path - Input path.
155
+ * @returns The extension (e.g., ".txt") or an empty string if none.
156
156
  */ static extname(path) {
157
157
  const basename = this.basename(path);
158
158
  const lastDot = basename.lastIndexOf('.');
159
159
  return lastDot === -1 ? '' : basename.slice(lastDot);
160
160
  }
161
- /**
162
- * Sanitizes a file or directory name by replacing or removing invalid characters.
163
- *
164
- * Behavior:
165
- * - Removes or replaces characters that are invalid in common filesystems.
166
- * - Trims leading/trailing spaces and dots.
167
- * - Collapses multiple spaces into single spaces.
168
- * - Replaces reserved names with safe alternatives.
169
- * - Optionally limits the length of the result.
170
- *
171
- * Examples:
172
- * - sanitizeFilename('my file.txt') -\> 'my file.txt'
173
- * - sanitizeFilename('file:name*.txt') -\> 'file_name_.txt'
174
- * - sanitizeFilename(' .hidden ') -\> 'hidden'
175
- * - sanitizeFilename('CON') -\> '_CON'
176
- * - sanitizeFilename('a'.repeat(300)) -\> (truncated to maxLength)
177
- *
178
- * @param filename - Input filename to sanitize.
179
- * @param options - Optional configuration.
180
- * @returns Sanitized filename safe for use across platforms.
161
+ /**
162
+ * Sanitizes a file or directory name by replacing or removing invalid characters.
163
+ *
164
+ * Behavior:
165
+ * - Removes or replaces characters that are invalid in common filesystems.
166
+ * - Trims leading/trailing spaces and dots.
167
+ * - Collapses multiple spaces into single spaces.
168
+ * - Replaces reserved names with safe alternatives.
169
+ * - Optionally limits the length of the result.
170
+ *
171
+ * Examples:
172
+ * - sanitizeFilename('my file.txt') -\> 'my file.txt'
173
+ * - sanitizeFilename('file:name*.txt') -\> 'file_name_.txt'
174
+ * - sanitizeFilename(' .hidden ') -\> 'hidden'
175
+ * - sanitizeFilename('CON') -\> '_CON'
176
+ * - sanitizeFilename('a'.repeat(300)) -\> (truncated to maxLength)
177
+ *
178
+ * @param filename - Input filename to sanitize.
179
+ * @param options - Optional configuration.
180
+ * @returns Sanitized filename safe for use across platforms.
181
181
  */ static sanitizeFilename(filename, options) {
182
182
  const { replacement = '_', maxLength = 255, asciiOnly = false } = options ?? {};
183
183
  const reserved = /^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i;
@@ -218,32 +218,32 @@ const mimeTypes = {
218
218
  }
219
219
  return sanitized;
220
220
  }
221
- /**
222
- * Determines whether the path is absolute.
223
- *
224
- * Definition here: absolute paths start with "/".
225
- *
226
- * @param path - Input path.
227
- * @returns True if the path starts with "/", otherwise false.
221
+ /**
222
+ * Determines whether the path is absolute.
223
+ *
224
+ * Definition here: absolute paths start with "/".
225
+ *
226
+ * @param path - Input path.
227
+ * @returns True if the path starts with "/", otherwise false.
228
228
  */ static isAbsolute(path) {
229
229
  return path.startsWith('/');
230
230
  }
231
- /**
232
- * Computes a relative path from one path to another.
233
- *
234
- * Behavior:
235
- * - Both `from` and `to` are normalized first.
236
- * - The returned path does not start with "/" (relative form).
237
- * - If both resolve to the same path, returns ".".
238
- *
239
- * Examples:
240
- * - relative('/a/b/c', '/a/d/e') -\> '../../d/e'
241
- * - relative('/a/b', '/a/b/c') -\> 'c'
242
- * - relative('/a/b', '/a/b') -\> '.'
243
- *
244
- * @param from - Base path to start from.
245
- * @param to - Target path to reach.
246
- * @returns Relative path from `from` to `to`.
231
+ /**
232
+ * Computes a relative path from one path to another.
233
+ *
234
+ * Behavior:
235
+ * - Both `from` and `to` are normalized first.
236
+ * - The returned path does not start with "/" (relative form).
237
+ * - If both resolve to the same path, returns ".".
238
+ *
239
+ * Examples:
240
+ * - relative('/a/b/c', '/a/d/e') -\> '../../d/e'
241
+ * - relative('/a/b', '/a/b/c') -\> 'c'
242
+ * - relative('/a/b', '/a/b') -\> '.'
243
+ *
244
+ * @param from - Base path to start from.
245
+ * @param to - Target path to reach.
246
+ * @returns Relative path from `from` to `to`.
247
247
  */ static relative(from, to) {
248
248
  const fromParts = this.normalize(from).split('/').filter(Boolean);
249
249
  const toParts = this.normalize(to).split('/').filter(Boolean);
@@ -256,37 +256,37 @@ const mimeTypes = {
256
256
  return up + down || '.';
257
257
  }
258
258
  }
259
- /**
260
- * Guesses the MIME type based on a file path or file name.
261
- *
262
- * Behavior:
263
- * - Uses `PathUtils.extname` to extract the extension (case-insensitive).
264
- * - Falls back to `application/octet-stream` if unknown.
265
- *
266
- * Notes:
267
- * - The mapping is intentionally minimal and web-oriented.
268
- * - Extend the `mimeTypes` table if you need additional types.
269
- *
270
- * Examples:
271
- * - guessMimeType('image.png') -\> 'image/png'
272
- * - guessMimeType('/a/b/model.glb') -\> 'model/gltf-binary'
273
- * - guessMimeType('unknown.ext') -\> 'application/octet-stream'
274
- *
275
- * @param path - File path or name used to infer the MIME type.
276
- * @returns The guessed MIME type string.
277
- *
278
- * @public
259
+ /**
260
+ * Guesses the MIME type based on a file path or file name.
261
+ *
262
+ * Behavior:
263
+ * - Uses `PathUtils.extname` to extract the extension (case-insensitive).
264
+ * - Falls back to `application/octet-stream` if unknown.
265
+ *
266
+ * Notes:
267
+ * - The mapping is intentionally minimal and web-oriented.
268
+ * - Extend the `mimeTypes` table if you need additional types.
269
+ *
270
+ * Examples:
271
+ * - guessMimeType('image.png') -\> 'image/png'
272
+ * - guessMimeType('/a/b/model.glb') -\> 'model/gltf-binary'
273
+ * - guessMimeType('unknown.ext') -\> 'application/octet-stream'
274
+ *
275
+ * @param path - File path or name used to infer the MIME type.
276
+ * @returns The guessed MIME type string.
277
+ *
278
+ * @public
279
279
  */ function guessMimeType(path) {
280
280
  const ext = PathUtils.extname(path).toLowerCase();
281
281
  return mimeTypes[ext] || 'application/octet-stream';
282
282
  }
283
- /**
284
- * Gets the MIME type based on a file extension.
285
- *
286
- * @param ext - File extension (e.g., "png", ".jpg").
287
- * @returns The corresponding MIME type or 'application/octet-stream' if unknown.
288
- *
289
- * @public
283
+ /**
284
+ * Gets the MIME type based on a file extension.
285
+ *
286
+ * @param ext - File extension (e.g., "png", ".jpg").
287
+ * @returns The corresponding MIME type or 'application/octet-stream' if unknown.
288
+ *
289
+ * @public
290
290
  */ function mimeTypeOf(ext) {
291
291
  ext = ext.toLowerCase();
292
292
  if (!ext.startsWith('.')) {
@@ -1 +1 @@
1
- {"version":3,"file":"common.js","sources":["../../src/vfs/common.ts"],"sourcesContent":["const mimeTypes: Record<string, string> = {\r\n '.txt': 'text/plain',\r\n '.html': 'text/html',\r\n '.js': 'text/javascript',\r\n '.mjs': 'text/javascript',\r\n '.ts': 'text/x-typescript',\r\n '.wasm': 'application/wasm',\r\n '.json': 'application/json',\r\n '.png': 'image/png',\r\n '.jpg': 'image/jpeg',\r\n '.jpeg': 'image/jpeg',\r\n '.webp': 'image/webp',\r\n '.gif': 'image/gif',\r\n '.tga': 'image/tga',\r\n '.ico': 'image/x-icon',\r\n '.dds': 'image/x-dds',\r\n '.svg': 'image/svg+xml',\r\n '.hdr': 'image/vnd.radiance',\r\n '.exr': 'image/x-exr',\r\n '.tiff': 'image/tiff',\r\n '.wav': 'audio/wav',\r\n '.mp3': 'audio/mpeg',\r\n '.mp4': 'video/mp4',\r\n '.zip': 'application/zip',\r\n '.fbx': 'model/fbx',\r\n '.obj': 'model/obj',\r\n '.gltf': 'model/gltf+json',\r\n '.glb': 'model/gltf-binary',\r\n '.vrm': 'model/gltf-binary',\r\n '.vrma': 'model/gltf-binary',\r\n '.ktx': 'image/ktx',\r\n '.ktx2': 'image/ktx2',\r\n '.ttf': 'font/ttf',\r\n '.otf': 'font/otf',\r\n // zephyr3d specific\r\n '.zbpt': 'application/vnd.zephyr3d.blueprint+json',\r\n '.zmsh': 'application/vnd.zephyr3d.mesh+json',\r\n '.zmtl': 'application/vnd.zephyr3d.material+json',\r\n '.zmf': 'application/vnd.zephyr3d.blueprint.mf+json',\r\n '.zscn': 'application/vnd.zephyr3d.scene+json',\r\n '.zprefab': 'application/vnd.zephyr3d.prefab+json',\r\n '.zabc': 'application/vnd.zephyr3d.alembic-cache+json'\r\n};\r\n\r\n/**\r\n * Path utilities.\r\n *\r\n * Provides POSIX-like path manipulation helpers (pure string operations),\r\n * including normalization, joining, dirname/basename/extname extraction,\r\n * absolute-path detection, and relative path computation.\r\n *\r\n * Notes:\r\n * - Uses \"/\" as the separator (web/URL or POSIX-like paths).\r\n * - All methods are pure and do not touch a real filesystem.\r\n * - `normalize` collapses \".\", \"..\", and redundant slashes.\r\n *\r\n * @public\r\n */\r\nexport class PathUtils {\r\n /**\r\n * Normalizes a path by collapsing redundant slashes, removing \".\" segments,\r\n * and resolving \"..\" segments.\r\n *\r\n * Rules:\r\n * - Multiple consecutive \"/\" are collapsed into a single \"/\".\r\n * - \".\" segments are removed.\r\n * - \"..\" removes the previous segment (no-op at root).\r\n * - The result always starts with \"/\" (absolute form).\r\n *\r\n * Example:\r\n * - normalize('/a//b/./c/../d') -\\> '/a/b/d'\r\n *\r\n * @param path - Input path (relative or absolute).\r\n * @returns The normalized absolute path (always starting with \"/\").\r\n */\r\n static normalize(path: string) {\r\n const parts = path.split('/').filter((p) => p && p !== '.');\r\n const result: string[] = [];\r\n\r\n for (const part of parts) {\r\n if (part === '..') {\r\n result.pop();\r\n } else {\r\n result.push(part);\r\n }\r\n }\r\n\r\n return '/' + result.join('/');\r\n }\r\n\r\n /**\r\n * Joins multiple path segments and normalizes the result.\r\n *\r\n * Behavior:\r\n * - Concatenates segments with \"/\" and then runs `normalize`.\r\n * - The returned path is always absolute.\r\n *\r\n * Example:\r\n * - join('/a', 'b', '../c') -\\> '/a/c'\r\n *\r\n * @param paths - Path segments in order.\r\n * @returns Normalized absolute path.\r\n */\r\n static join(...paths: string[]) {\r\n return this.normalize(paths.join('/'));\r\n }\r\n\r\n /**\r\n * Returns the directory name (parent directory) of a path.\r\n *\r\n * Behavior:\r\n * - Applies `normalize` first.\r\n * - If the path is root \"/\" or has no parent, returns \"/\".\r\n *\r\n * Examples:\r\n * - dirname('/a/b/c') -\\> '/a/b'\r\n * - dirname('/a') -\\> '/'\r\n * - dirname('/') -\\> '/'\r\n *\r\n * @param path - Input path.\r\n * @returns Directory path of the input.\r\n */\r\n static dirname(path: string) {\r\n const normalized = this.normalize(path);\r\n const lastSlash = normalized.lastIndexOf('/');\r\n return lastSlash <= 0 ? '/' : normalized.slice(0, lastSlash);\r\n }\r\n\r\n /**\r\n * Returns the last portion of a path (file name).\r\n *\r\n * Behavior:\r\n * - Applies `normalize` first.\r\n * - If `ext` is provided and the name ends with it, the extension is stripped.\r\n *\r\n * Examples:\r\n * - basename('/a/b/c.txt') -\\> 'c.txt'\r\n * - basename('/a/b/c.txt', '.txt') -\\> 'c'\r\n * - basename('/') -\\> ''\r\n *\r\n * @param path - Input path.\r\n * @param ext - Optional extension to strip (exact suffix match).\r\n * @returns The base name of the path.\r\n */\r\n static basename(path: string, ext?: string) {\r\n const normalized = this.normalize(path);\r\n const lastSlash = normalized.lastIndexOf('/');\r\n let name = normalized.slice(lastSlash + 1);\r\n\r\n if (ext && name.endsWith(ext)) {\r\n name = name.slice(0, -ext.length);\r\n }\r\n\r\n return name;\r\n }\r\n\r\n /**\r\n * Returns the extension of the path, including the leading dot.\r\n *\r\n * Behavior:\r\n * - Based on the result of `basename`.\r\n * - If there is no dot, returns an empty string.\r\n *\r\n * Examples:\r\n * - extname('/a/b/c.txt') -\\> '.txt'\r\n * - extname('/a/b/c') -\\> ''\r\n *\r\n * @param path - Input path.\r\n * @returns The extension (e.g., \".txt\") or an empty string if none.\r\n */\r\n static extname(path: string) {\r\n const basename = this.basename(path);\r\n const lastDot = basename.lastIndexOf('.');\r\n return lastDot === -1 ? '' : basename.slice(lastDot);\r\n }\r\n\r\n /**\r\n * Sanitizes a file or directory name by replacing or removing invalid characters.\r\n *\r\n * Behavior:\r\n * - Removes or replaces characters that are invalid in common filesystems.\r\n * - Trims leading/trailing spaces and dots.\r\n * - Collapses multiple spaces into single spaces.\r\n * - Replaces reserved names with safe alternatives.\r\n * - Optionally limits the length of the result.\r\n *\r\n * Examples:\r\n * - sanitizeFilename('my file.txt') -\\> 'my file.txt'\r\n * - sanitizeFilename('file:name*.txt') -\\> 'file_name_.txt'\r\n * - sanitizeFilename(' .hidden ') -\\> 'hidden'\r\n * - sanitizeFilename('CON') -\\> '_CON'\r\n * - sanitizeFilename('a'.repeat(300)) -\\> (truncated to maxLength)\r\n *\r\n * @param filename - Input filename to sanitize.\r\n * @param options - Optional configuration.\r\n * @returns Sanitized filename safe for use across platforms.\r\n */\r\n static sanitizeFilename(\r\n filename: string,\r\n options?: { replacement?: string; maxLength?: number; asciiOnly?: boolean }\r\n ) {\r\n const { replacement = '_', maxLength = 255, asciiOnly = false } = options ?? {};\r\n const reserved = /^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i;\r\n\r\n // Replace reserved special characters\r\n let sanitized = filename.replace(/[<>:\"/\\\\|?*]/g, replacement);\r\n // Replace control characters and optionally non-ASCII\r\n sanitized = Array.from(sanitized)\r\n .map((char) => {\r\n const code = char.charCodeAt(0);\r\n if (code <= 0x1f || code === 0x7f) {\r\n return replacement;\r\n }\r\n if (asciiOnly && (code < 0x20 || code > 0x7e)) {\r\n return replacement;\r\n }\r\n return char;\r\n })\r\n .join('');\r\n // Normalize whitespace and trim invalid edges\r\n sanitized = sanitized.replace(/\\s+/g, ' ').replace(/^[\\s.]+|[\\s.]+$/g, '');\r\n // Empty fallback\r\n if (!sanitized) {\r\n sanitized = 'unnamed';\r\n }\r\n // Handle reserved names (Windows)\r\n const baseName = sanitized.split('.')[0];\r\n if (reserved.test(baseName)) {\r\n sanitized = replacement + sanitized;\r\n }\r\n // Truncate (preserve extension if possible)\r\n if (sanitized.length > maxLength) {\r\n const dotIndex = sanitized.lastIndexOf('.');\r\n if (dotIndex > 0 && sanitized.length - dotIndex <= 10) {\r\n const ext = sanitized.slice(dotIndex);\r\n const base = sanitized.slice(0, maxLength - ext.length);\r\n sanitized = base + ext;\r\n } else {\r\n sanitized = sanitized.slice(0, maxLength);\r\n }\r\n }\r\n\r\n return sanitized;\r\n }\r\n /**\r\n * Determines whether the path is absolute.\r\n *\r\n * Definition here: absolute paths start with \"/\".\r\n *\r\n * @param path - Input path.\r\n * @returns True if the path starts with \"/\", otherwise false.\r\n */\r\n static isAbsolute(path: string) {\r\n return path.startsWith('/');\r\n }\r\n\r\n /**\r\n * Computes a relative path from one path to another.\r\n *\r\n * Behavior:\r\n * - Both `from` and `to` are normalized first.\r\n * - The returned path does not start with \"/\" (relative form).\r\n * - If both resolve to the same path, returns \".\".\r\n *\r\n * Examples:\r\n * - relative('/a/b/c', '/a/d/e') -\\> '../../d/e'\r\n * - relative('/a/b', '/a/b/c') -\\> 'c'\r\n * - relative('/a/b', '/a/b') -\\> '.'\r\n *\r\n * @param from - Base path to start from.\r\n * @param to - Target path to reach.\r\n * @returns Relative path from `from` to `to`.\r\n */\r\n static relative(from: string, to: string) {\r\n const fromParts = this.normalize(from).split('/').filter(Boolean);\r\n const toParts = this.normalize(to).split('/').filter(Boolean);\r\n\r\n let i = 0;\r\n while (i < fromParts.length && i < toParts.length && fromParts[i] === toParts[i]) {\r\n i++;\r\n }\r\n\r\n const up = '../'.repeat(fromParts.length - i);\r\n const down = toParts.slice(i).join('/');\r\n\r\n return up + down || '.';\r\n }\r\n}\r\n\r\n/**\r\n * Guesses the MIME type based on a file path or file name.\r\n *\r\n * Behavior:\r\n * - Uses `PathUtils.extname` to extract the extension (case-insensitive).\r\n * - Falls back to `application/octet-stream` if unknown.\r\n *\r\n * Notes:\r\n * - The mapping is intentionally minimal and web-oriented.\r\n * - Extend the `mimeTypes` table if you need additional types.\r\n *\r\n * Examples:\r\n * - guessMimeType('image.png') -\\> 'image/png'\r\n * - guessMimeType('/a/b/model.glb') -\\> 'model/gltf-binary'\r\n * - guessMimeType('unknown.ext') -\\> 'application/octet-stream'\r\n *\r\n * @param path - File path or name used to infer the MIME type.\r\n * @returns The guessed MIME type string.\r\n *\r\n * @public\r\n */\r\nexport function guessMimeType(path: string) {\r\n const ext = PathUtils.extname(path).toLowerCase();\r\n return mimeTypes[ext] || 'application/octet-stream';\r\n}\r\n\r\n/**\r\n * Gets the MIME type based on a file extension.\r\n *\r\n * @param ext - File extension (e.g., \"png\", \".jpg\").\r\n * @returns The corresponding MIME type or 'application/octet-stream' if unknown.\r\n *\r\n * @public\r\n */\r\nexport function mimeTypeOf(ext: string) {\r\n ext = ext.toLowerCase();\r\n if (!ext.startsWith('.')) {\r\n ext = '.' + ext;\r\n }\r\n return mimeTypes[ext] || 'application/octet-stream';\r\n}\r\n"],"names":["mimeTypes","PathUtils","normalize","path","parts","split","filter","p","result","part","pop","push","join","paths","dirname","normalized","lastSlash","lastIndexOf","slice","basename","ext","name","endsWith","length","extname","lastDot","sanitizeFilename","filename","options","replacement","maxLength","asciiOnly","reserved","sanitized","replace","Array","from","map","char","code","charCodeAt","baseName","test","dotIndex","base","isAbsolute","startsWith","relative","to","fromParts","Boolean","toParts","i","up","repeat","down","guessMimeType","toLowerCase","mimeTypeOf"],"mappings":"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"}
1
+ {"version":3,"file":"common.js","sources":["../../src/vfs/common.ts"],"sourcesContent":["const mimeTypes: Record<string, string> = {\n '.txt': 'text/plain',\n '.html': 'text/html',\n '.js': 'text/javascript',\n '.mjs': 'text/javascript',\n '.ts': 'text/x-typescript',\n '.wasm': 'application/wasm',\n '.json': 'application/json',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.webp': 'image/webp',\n '.gif': 'image/gif',\n '.tga': 'image/tga',\n '.ico': 'image/x-icon',\n '.dds': 'image/x-dds',\n '.svg': 'image/svg+xml',\n '.hdr': 'image/vnd.radiance',\n '.exr': 'image/x-exr',\n '.tiff': 'image/tiff',\n '.wav': 'audio/wav',\n '.mp3': 'audio/mpeg',\n '.mp4': 'video/mp4',\n '.zip': 'application/zip',\n '.fbx': 'model/fbx',\n '.obj': 'model/obj',\n '.gltf': 'model/gltf+json',\n '.glb': 'model/gltf-binary',\n '.vrm': 'model/gltf-binary',\n '.vrma': 'model/gltf-binary',\n '.ktx': 'image/ktx',\n '.ktx2': 'image/ktx2',\n '.ttf': 'font/ttf',\n '.otf': 'font/otf',\n // zephyr3d specific\n '.zbpt': 'application/vnd.zephyr3d.blueprint+json',\n '.zmsh': 'application/vnd.zephyr3d.mesh+json',\n '.zmtl': 'application/vnd.zephyr3d.material+json',\n '.zmf': 'application/vnd.zephyr3d.blueprint.mf+json',\n '.zscn': 'application/vnd.zephyr3d.scene+json',\n '.zprefab': 'application/vnd.zephyr3d.prefab+json',\n '.zabc': 'application/vnd.zephyr3d.alembic-cache+json'\n};\n\n/**\n * Path utilities.\n *\n * Provides POSIX-like path manipulation helpers (pure string operations),\n * including normalization, joining, dirname/basename/extname extraction,\n * absolute-path detection, and relative path computation.\n *\n * Notes:\n * - Uses \"/\" as the separator (web/URL or POSIX-like paths).\n * - All methods are pure and do not touch a real filesystem.\n * - `normalize` collapses \".\", \"..\", and redundant slashes.\n *\n * @public\n */\nexport class PathUtils {\n /**\n * Normalizes a path by collapsing redundant slashes, removing \".\" segments,\n * and resolving \"..\" segments.\n *\n * Rules:\n * - Multiple consecutive \"/\" are collapsed into a single \"/\".\n * - \".\" segments are removed.\n * - \"..\" removes the previous segment (no-op at root).\n * - The result always starts with \"/\" (absolute form).\n *\n * Example:\n * - normalize('/a//b/./c/../d') -\\> '/a/b/d'\n *\n * @param path - Input path (relative or absolute).\n * @returns The normalized absolute path (always starting with \"/\").\n */\n static normalize(path: string) {\n const parts = path.split('/').filter((p) => p && p !== '.');\n const result: string[] = [];\n\n for (const part of parts) {\n if (part === '..') {\n result.pop();\n } else {\n result.push(part);\n }\n }\n\n return '/' + result.join('/');\n }\n\n /**\n * Joins multiple path segments and normalizes the result.\n *\n * Behavior:\n * - Concatenates segments with \"/\" and then runs `normalize`.\n * - The returned path is always absolute.\n *\n * Example:\n * - join('/a', 'b', '../c') -\\> '/a/c'\n *\n * @param paths - Path segments in order.\n * @returns Normalized absolute path.\n */\n static join(...paths: string[]) {\n return this.normalize(paths.join('/'));\n }\n\n /**\n * Returns the directory name (parent directory) of a path.\n *\n * Behavior:\n * - Applies `normalize` first.\n * - If the path is root \"/\" or has no parent, returns \"/\".\n *\n * Examples:\n * - dirname('/a/b/c') -\\> '/a/b'\n * - dirname('/a') -\\> '/'\n * - dirname('/') -\\> '/'\n *\n * @param path - Input path.\n * @returns Directory path of the input.\n */\n static dirname(path: string) {\n const normalized = this.normalize(path);\n const lastSlash = normalized.lastIndexOf('/');\n return lastSlash <= 0 ? '/' : normalized.slice(0, lastSlash);\n }\n\n /**\n * Returns the last portion of a path (file name).\n *\n * Behavior:\n * - Applies `normalize` first.\n * - If `ext` is provided and the name ends with it, the extension is stripped.\n *\n * Examples:\n * - basename('/a/b/c.txt') -\\> 'c.txt'\n * - basename('/a/b/c.txt', '.txt') -\\> 'c'\n * - basename('/') -\\> ''\n *\n * @param path - Input path.\n * @param ext - Optional extension to strip (exact suffix match).\n * @returns The base name of the path.\n */\n static basename(path: string, ext?: string) {\n const normalized = this.normalize(path);\n const lastSlash = normalized.lastIndexOf('/');\n let name = normalized.slice(lastSlash + 1);\n\n if (ext && name.endsWith(ext)) {\n name = name.slice(0, -ext.length);\n }\n\n return name;\n }\n\n /**\n * Returns the extension of the path, including the leading dot.\n *\n * Behavior:\n * - Based on the result of `basename`.\n * - If there is no dot, returns an empty string.\n *\n * Examples:\n * - extname('/a/b/c.txt') -\\> '.txt'\n * - extname('/a/b/c') -\\> ''\n *\n * @param path - Input path.\n * @returns The extension (e.g., \".txt\") or an empty string if none.\n */\n static extname(path: string) {\n const basename = this.basename(path);\n const lastDot = basename.lastIndexOf('.');\n return lastDot === -1 ? '' : basename.slice(lastDot);\n }\n\n /**\n * Sanitizes a file or directory name by replacing or removing invalid characters.\n *\n * Behavior:\n * - Removes or replaces characters that are invalid in common filesystems.\n * - Trims leading/trailing spaces and dots.\n * - Collapses multiple spaces into single spaces.\n * - Replaces reserved names with safe alternatives.\n * - Optionally limits the length of the result.\n *\n * Examples:\n * - sanitizeFilename('my file.txt') -\\> 'my file.txt'\n * - sanitizeFilename('file:name*.txt') -\\> 'file_name_.txt'\n * - sanitizeFilename(' .hidden ') -\\> 'hidden'\n * - sanitizeFilename('CON') -\\> '_CON'\n * - sanitizeFilename('a'.repeat(300)) -\\> (truncated to maxLength)\n *\n * @param filename - Input filename to sanitize.\n * @param options - Optional configuration.\n * @returns Sanitized filename safe for use across platforms.\n */\n static sanitizeFilename(\n filename: string,\n options?: { replacement?: string; maxLength?: number; asciiOnly?: boolean }\n ) {\n const { replacement = '_', maxLength = 255, asciiOnly = false } = options ?? {};\n const reserved = /^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i;\n\n // Replace reserved special characters\n let sanitized = filename.replace(/[<>:\"/\\\\|?*]/g, replacement);\n // Replace control characters and optionally non-ASCII\n sanitized = Array.from(sanitized)\n .map((char) => {\n const code = char.charCodeAt(0);\n if (code <= 0x1f || code === 0x7f) {\n return replacement;\n }\n if (asciiOnly && (code < 0x20 || code > 0x7e)) {\n return replacement;\n }\n return char;\n })\n .join('');\n // Normalize whitespace and trim invalid edges\n sanitized = sanitized.replace(/\\s+/g, ' ').replace(/^[\\s.]+|[\\s.]+$/g, '');\n // Empty fallback\n if (!sanitized) {\n sanitized = 'unnamed';\n }\n // Handle reserved names (Windows)\n const baseName = sanitized.split('.')[0];\n if (reserved.test(baseName)) {\n sanitized = replacement + sanitized;\n }\n // Truncate (preserve extension if possible)\n if (sanitized.length > maxLength) {\n const dotIndex = sanitized.lastIndexOf('.');\n if (dotIndex > 0 && sanitized.length - dotIndex <= 10) {\n const ext = sanitized.slice(dotIndex);\n const base = sanitized.slice(0, maxLength - ext.length);\n sanitized = base + ext;\n } else {\n sanitized = sanitized.slice(0, maxLength);\n }\n }\n\n return sanitized;\n }\n /**\n * Determines whether the path is absolute.\n *\n * Definition here: absolute paths start with \"/\".\n *\n * @param path - Input path.\n * @returns True if the path starts with \"/\", otherwise false.\n */\n static isAbsolute(path: string) {\n return path.startsWith('/');\n }\n\n /**\n * Computes a relative path from one path to another.\n *\n * Behavior:\n * - Both `from` and `to` are normalized first.\n * - The returned path does not start with \"/\" (relative form).\n * - If both resolve to the same path, returns \".\".\n *\n * Examples:\n * - relative('/a/b/c', '/a/d/e') -\\> '../../d/e'\n * - relative('/a/b', '/a/b/c') -\\> 'c'\n * - relative('/a/b', '/a/b') -\\> '.'\n *\n * @param from - Base path to start from.\n * @param to - Target path to reach.\n * @returns Relative path from `from` to `to`.\n */\n static relative(from: string, to: string) {\n const fromParts = this.normalize(from).split('/').filter(Boolean);\n const toParts = this.normalize(to).split('/').filter(Boolean);\n\n let i = 0;\n while (i < fromParts.length && i < toParts.length && fromParts[i] === toParts[i]) {\n i++;\n }\n\n const up = '../'.repeat(fromParts.length - i);\n const down = toParts.slice(i).join('/');\n\n return up + down || '.';\n }\n}\n\n/**\n * Guesses the MIME type based on a file path or file name.\n *\n * Behavior:\n * - Uses `PathUtils.extname` to extract the extension (case-insensitive).\n * - Falls back to `application/octet-stream` if unknown.\n *\n * Notes:\n * - The mapping is intentionally minimal and web-oriented.\n * - Extend the `mimeTypes` table if you need additional types.\n *\n * Examples:\n * - guessMimeType('image.png') -\\> 'image/png'\n * - guessMimeType('/a/b/model.glb') -\\> 'model/gltf-binary'\n * - guessMimeType('unknown.ext') -\\> 'application/octet-stream'\n *\n * @param path - File path or name used to infer the MIME type.\n * @returns The guessed MIME type string.\n *\n * @public\n */\nexport function guessMimeType(path: string) {\n const ext = PathUtils.extname(path).toLowerCase();\n return mimeTypes[ext] || 'application/octet-stream';\n}\n\n/**\n * Gets the MIME type based on a file extension.\n *\n * @param ext - File extension (e.g., \"png\", \".jpg\").\n * @returns The corresponding MIME type or 'application/octet-stream' if unknown.\n *\n * @public\n */\nexport function mimeTypeOf(ext: string) {\n ext = ext.toLowerCase();\n if (!ext.startsWith('.')) {\n ext = '.' + ext;\n }\n return mimeTypes[ext] || 'application/octet-stream';\n}\n"],"names":["mimeTypes","PathUtils","normalize","path","parts","split","filter","p","result","part","pop","push","join","paths","dirname","normalized","lastSlash","lastIndexOf","slice","basename","ext","name","endsWith","length","extname","lastDot","sanitizeFilename","filename","options","replacement","maxLength","asciiOnly","reserved","sanitized","replace","Array","from","map","char","code","charCodeAt","baseName","test","dotIndex","base","isAbsolute","startsWith","relative","to","fromParts","Boolean","toParts","i","up","repeat","down","guessMimeType","toLowerCase","mimeTypeOf"],"mappings":"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"}
@@ -60,18 +60,18 @@ class ResizeHandler {
60
60
  const cssWidth = boxSize?.inlineSize ?? this._canvas.clientWidth;
61
61
  const cssHeight = boxSize?.blockSize ?? this._canvas.clientHeight;
62
62
  // Device pixel
63
- /*
64
- let deviceWidth: number;
65
- let deviceHeight: number;
66
-
67
- const dpBox = (entry as any).devicePixelContentBoxSize?.[0];
68
- if (dpBox) {
69
- deviceWidth = dpBox.inlineSize;
70
- deviceHeight = dpBox.blockSize;
71
- } else {
72
- deviceWidth = Math.round(cssWidth * this._dpr);
73
- deviceHeight = Math.round(cssHeight * this._dpr);
74
- }
63
+ /*
64
+ let deviceWidth: number;
65
+ let deviceHeight: number;
66
+
67
+ const dpBox = (entry as any).devicePixelContentBoxSize?.[0];
68
+ if (dpBox) {
69
+ deviceWidth = dpBox.inlineSize;
70
+ deviceHeight = dpBox.blockSize;
71
+ } else {
72
+ deviceWidth = Math.round(cssWidth * this._dpr);
73
+ deviceHeight = Math.round(cssHeight * this._dpr);
74
+ }
75
75
  */ const deviceWidth = cssWidth * this._dpr;
76
76
  const deviceHeight = cssHeight * this._dpr;
77
77
  if (cssWidth === this._cssWidth && cssHeight === this._cssHeight && deviceWidth === this._deviceWidth && deviceHeight === this._deviceHeight) {
@@ -108,9 +108,9 @@ class ResizeHandler {
108
108
  window.removeEventListener('resize', this._handleLegacyResize);
109
109
  }
110
110
  }
111
- /**
112
- * Base class for rendering device
113
- * @public
111
+ /**
112
+ * Base class for rendering device
113
+ * @public
114
114
  */ class BaseDevice extends Observable {
115
115
  _dpr;
116
116
  _canvas;