@volter/editor-blender 0.1.36 → 0.1.38

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.
@@ -646,10 +646,14 @@ function BlenderViewportArea({
646
646
  // WHERE BLENDER OPENS THE FILE: its own saved 3D View, when it holds one; the direction and
647
647
  // fit above are the fallback for a file that saved none.
648
648
  openingView={view.savedView()}
649
- // The file's own lens, as the document's presentation (Blender's arithmetic in degrees).
649
+ // The file's own lens (Blender's arithmetic in degrees) and the shading its view was saved
650
+ // in, as the document's presentation: Blender reopens a file saved in Material Preview in
651
+ // Material Preview, so a textured scene saved that way does not open grey.
650
652
  presentation={(() => {
651
653
  const saved = view.savedView();
652
- return saved ? { camera: { fov: blenderViewFieldOfView(saved.lens) } } : null;
654
+ if (!saved) return null;
655
+ const camera = { fov: blenderViewFieldOfView(saved.lens) };
656
+ return saved.drawMode ? { camera, drawMode: saved.drawMode } : { camera };
653
657
  })()}
654
658
  // Every entry this document opens is a `model` stage, the standing `blender:runtime`
655
659
  // address included (its id carries no `model:` prefix).
@@ -227,7 +227,8 @@ async function runtimeIndex(dir) {
227
227
  files.push({
228
228
  path: relative(root, path).split(/[\\/]/).join(posix.sep),
229
229
  size: info.size,
230
- mode: info.mode & 4095
230
+ mode: info.mode & 4095,
231
+ sha256: createHash("sha256").update(await readFile(path)).digest("hex")
231
232
  });
232
233
  newest = Math.max(newest, info.mtimeMs);
233
234
  }
@@ -239,8 +240,10 @@ async function runtimeIndex(dir) {
239
240
  return index;
240
241
  }
241
242
  function runtimeTag(index) {
242
- const total = index.files.reduce((sum, file) => sum + file.size, 0);
243
- return `"runtime-${index.files.length}-${total}-${Math.floor(index.newestMtimeMs ?? 0)}"`;
243
+ const contents = createHash("sha256");
244
+ for (const file of index.files) contents.update(`${file.path}\0${file.mode}\0${file.sha256}
245
+ `);
246
+ return `"runtime-${index.files.length}-${contents.digest("hex").slice(0, 24)}"`;
244
247
  }
245
248
  async function writeRuntimeBlob(dir, write) {
246
249
  const root = join(dir, BLENDER_WALI_RUNTIME);
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@volter/editor-blender",
3
3
  "author": "Volter AI, Inc.",
4
4
  "license": "AGPL-3.0-only AND GPL-3.0-or-later",
5
- "version": "0.1.36",
5
+ "version": "0.1.38",
6
6
  "publishConfig": {
7
7
  "access": "public"
8
8
  },
@@ -70,14 +70,14 @@
70
70
  },
71
71
  "dependencies": {
72
72
  "@modelcontextprotocol/sdk": "1.30.0",
73
- "@volter/blender-engine": "0.1.34",
74
- "@volter/editor-threejs": "0.5.96",
73
+ "@volter/blender-engine": "0.1.36",
74
+ "@volter/editor-threejs": "0.5.98",
75
75
  "zod": "^4.3.6"
76
76
  },
77
77
  "peerDependencies": {
78
- "@volter/editor-live": "0.5.96",
79
- "@volter/editor-project": "0.5.96",
80
- "@volter/editor-sdk": "0.5.96",
78
+ "@volter/editor-live": "0.5.98",
79
+ "@volter/editor-project": "0.5.98",
80
+ "@volter/editor-sdk": "0.5.98",
81
81
  "react": "^19.0.0",
82
82
  "react-dom": "^19.0.0",
83
83
  "three": "^0.180.0",
@@ -355,8 +355,10 @@ export function blenderWasmReadStream(found: BlenderWasmOnDisk): NodeJS.Readable
355
355
  // ---- The WALI skew: the runtime tree, and the substrate that runs the program.
356
356
 
357
357
  export interface RuntimeIndex {
358
- files: { path: string; size: number; mode: number }[];
359
- /** The newest file's modification time: with the count and the total size, the blob's validator (`runtimeTag`). */
358
+ /** Each file with its content's SHA-256: a file rebuilt at the same size and an older time is
359
+ * still a new file, and everything that names the tree by its index (the tab's OPFS store,
360
+ * `runtimeTag`, the compressed blob's cache) must see it. */
361
+ files: { path: string; size: number; mode: number; sha256: string }[];
360
362
  newestMtimeMs?: number;
361
363
  }
362
364
 
@@ -392,6 +394,7 @@ export async function runtimeIndex(dir: string): Promise<RuntimeIndex> {
392
394
  path: relative(root, path).split(/[\\/]/).join(posix.sep),
393
395
  size: info.size,
394
396
  mode: info.mode & 0o7777,
397
+ sha256: createHash('sha256').update(await readFile(path)).digest('hex'),
395
398
  });
396
399
  newest = Math.max(newest, info.mtimeMs);
397
400
  }
@@ -410,8 +413,9 @@ export async function runtimeIndex(dir: string): Promise<RuntimeIndex> {
410
413
  * what the substrate skew's boot spent before Blender ran (2026-09-27).
411
414
  */
412
415
  export function runtimeTag(index: RuntimeIndex): string {
413
- const total = index.files.reduce((sum, file) => sum + file.size, 0);
414
- return `"runtime-${index.files.length}-${total}-${Math.floor(index.newestMtimeMs ?? 0)}"`;
416
+ const contents = createHash('sha256');
417
+ for (const file of index.files) contents.update(`${file.path}\0${file.mode}\0${file.sha256}\n`);
418
+ return `"runtime-${index.files.length}-${contents.digest('hex').slice(0, 24)}"`;
415
419
  }
416
420
 
417
421
  /** Stream the runtime blob: every indexed file's bytes, in index order. */