@volter/editor-blender 0.1.37 → 0.1.39

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.
@@ -56,7 +56,12 @@ import {
56
56
  useSyncExternalStore,
57
57
  } from 'react';
58
58
  import * as THREE from 'three';
59
- import { bindModelDocument, blenderExecute, openModelDocumentBlend } from '../host/blender-runtime-host';
59
+ import {
60
+ bindModelDocument,
61
+ blenderExecute,
62
+ blenderViewShading,
63
+ openModelDocumentBlend,
64
+ } from '../host/blender-runtime-host';
60
65
  import { BlenderObjectModeHeader } from './blender-header-menus';
61
66
  import { blenderOutlinerAuthoringFor, createBlenderOutlinerAuthoring } from './blender-outliner-authoring';
62
67
  import { blenderSkin } from './blender-runtime-skin';
@@ -124,6 +129,14 @@ export const inspectorBuiltins: readonly string[] = [];
124
129
  const view = blenderModelView;
125
130
  type AreaView = BlenderRuntimeView;
126
131
 
132
+ /** A stage draw mode as the `View3DShading.type` Blender saves it under. */
133
+ const BLENDER_SHADING = {
134
+ wireframe: 'WIREFRAME',
135
+ solid: 'SOLID',
136
+ preview: 'MATERIAL',
137
+ rendered: 'RENDERED',
138
+ } as const;
139
+
127
140
  /** What an area's stage reads from the view it draws, made once per view. */
128
141
  interface AreaReads {
129
142
  readonly subject: () => string | null;
@@ -431,6 +444,24 @@ function BlenderViewportArea({
431
444
  stopFrames();
432
445
  };
433
446
  }, [main, documentId, view]);
447
+ /**
448
+ * A SHADING PICK IS KEPT WHERE BLENDER KEEPS IT: in the file's own 3D View, the one it reopens
449
+ * on (`blenderViewShading`), so the next save carries it and a reopen starts from it. Noted on
450
+ * the view at once, so a remount before the next frame reads the pick and not the file's old
451
+ * shading. Modes Blender's four cells do not name (Clay, Matcap…) stay the editor's.
452
+ */
453
+ useEffect(() => {
454
+ if (!main || !documentId) return;
455
+ const keep = (): void => {
456
+ const saved = view.savedView();
457
+ const mode = viewPresentation(documentId).drawMode;
458
+ const shading = BLENDER_SHADING[mode as keyof typeof BLENDER_SHADING];
459
+ if (!saved || shading === undefined || saved.drawMode === mode) return;
460
+ view.noteSavedShading(shading);
461
+ void blenderViewShading(shading);
462
+ };
463
+ return subscribeViewportPresentation(keep);
464
+ }, [main, documentId, view]);
434
465
  /**
435
466
  * AND WITH THE AREA'S SHOW OVERLAYS OFF, the switch that makes a camera view read as the render
436
467
  * does: no grid, no camera or light wires, no selection marks, no view text — and still the
@@ -646,10 +677,15 @@ function BlenderViewportArea({
646
677
  // WHERE BLENDER OPENS THE FILE: its own saved 3D View, when it holds one; the direction and
647
678
  // fit above are the fallback for a file that saved none.
648
679
  openingView={view.savedView()}
649
- // The file's own lens, as the document's presentation (Blender's arithmetic in degrees).
680
+ // The file's own lens (Blender's arithmetic in degrees) and, for the main area, the shading
681
+ // its view was saved in, as the document's presentation: Blender reopens a file saved in
682
+ // Material Preview in Material Preview, so a textured scene saved that way does not open
683
+ // grey. The second area is the render preview and opens Rendered.
650
684
  presentation={(() => {
651
685
  const saved = view.savedView();
652
- return saved ? { camera: { fov: blenderViewFieldOfView(saved.lens) } } : null;
686
+ if (!saved) return null;
687
+ const camera = { fov: blenderViewFieldOfView(saved.lens) };
688
+ return main && saved.drawMode ? { camera, drawMode: saved.drawMode } : { camera };
653
689
  })()}
654
690
  // Every entry this document opens is a `model` stage, the standing `blender:runtime`
655
691
  // address included (its id carries no `model:` prefix).
@@ -444,6 +444,12 @@ export async function blenderRnaSet(
444
444
  return written;
445
445
  }
446
446
 
447
+ /** Keep a person's shading pick in the file's own 3D View (`runtime.viewShading`). */
448
+ export async function blenderViewShading(shading: 'WIREFRAME' | 'SOLID' | 'MATERIAL' | 'RENDERED'): Promise<void> {
449
+ if (!blenderSessionStarted()) return;
450
+ await blenderRuntime().viewShading(shading);
451
+ }
452
+
447
453
  /**
448
454
  * THE SCRIPT DOOR, in-page — one bpy script, run the way the MCP add-on runs
449
455
  * one (`session.py::execute`: a namespace of its own, output captured, and a
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.37",
5
+ "version": "0.1.39",
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.35",
74
- "@volter/editor-threejs": "0.5.97",
73
+ "@volter/blender-engine": "0.1.37",
74
+ "@volter/editor-threejs": "0.5.99",
75
75
  "zod": "^4.3.6"
76
76
  },
77
77
  "peerDependencies": {
78
- "@volter/editor-live": "0.5.97",
79
- "@volter/editor-project": "0.5.97",
80
- "@volter/editor-sdk": "0.5.97",
78
+ "@volter/editor-live": "0.5.99",
79
+ "@volter/editor-project": "0.5.99",
80
+ "@volter/editor-sdk": "0.5.99",
81
81
  "react": "^19.0.0",
82
82
  "react-dom": "^19.0.0",
83
83
  "three": "^0.180.0",