@volter/editor-threejs 0.5.141 → 0.5.143

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@volter/editor-threejs",
3
3
  "author": "Volter AI, Inc.",
4
- "version": "0.5.141",
4
+ "version": "0.5.143",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -135,12 +135,12 @@
135
135
  "serving": "./dist-node/serving.mjs"
136
136
  },
137
137
  "dependencies": {
138
- "@volter/editor-project": "0.5.141",
138
+ "@volter/editor-project": "0.5.143",
139
139
  "@sparkjsdev/spark": "^2.1.0",
140
140
  "three.quarks": "^0.16.0",
141
141
  "zod": "^4.3.6",
142
142
  "typescript": "5.9.3",
143
- "@volter/editor-sdk": "0.5.141",
143
+ "@volter/editor-sdk": "0.5.143",
144
144
  "postprocessing": "6.38.3",
145
145
  "quarks.core": "0.16.0",
146
146
  "@fortawesome/free-solid-svg-icons": "^7.2.0"
@@ -175,6 +175,7 @@ export class Object3DDocumentSession {
175
175
  /** The host's mirror of the document scene onto the rendered scene — see
176
176
  * {@link Object3DDocumentSession.setBeforeRender}. */
177
177
  private beforeRender: ((interactive: boolean) => void | (() => void)) | null = null;
178
+ private beforeDepthRender: ((camera: THREE.Camera, material: THREE.MeshDepthMaterial) => void | (() => void)) | null = null;
178
179
  private state = INITIAL_PRESENTATION;
179
180
  private version = 0;
180
181
  private readonly listeners = new Set<() => void>();
@@ -1253,8 +1254,10 @@ export class Object3DDocumentSession {
1253
1254
  * The host owns the step and clears it in its own teardown; the session only
1254
1255
  * holds the reference.
1255
1256
  */
1256
- setBeforeRender(step: ((interactive: boolean) => void | (() => void)) | null): void {
1257
+ setBeforeRender(step: ((interactive: boolean) => void | (() => void)) | null,
1258
+ depth: ((camera: THREE.Camera, material: THREE.MeshDepthMaterial) => void | (() => void)) | null = null): void {
1257
1259
  this.beforeRender = step;
1260
+ this.beforeDepthRender = step ? depth : null;
1258
1261
  }
1259
1262
 
1260
1263
  /**
@@ -1340,6 +1343,22 @@ export class Object3DDocumentSession {
1340
1343
 
1341
1344
  render(renderSolid: (camera: THREE.Camera) => void, interactive = false): void {
1342
1345
  const finishDraw = this.beforeRender?.(interactive);
1346
+ const before = this.scene.onBeforeRender;
1347
+ const after = this.scene.onAfterRender;
1348
+ const passCleanups: (void | (() => void))[] = [];
1349
+ // Public Scene hooks bracket each actual renderer pass, after matrices are
1350
+ // current and before its render list is built. A composer may render this
1351
+ // scene repeatedly with different cameras and override materials.
1352
+ this.scene.onBeforeRender = (...args) => {
1353
+ before.apply(this.scene, args);
1354
+ const material = this.scene.overrideMaterial as THREE.MeshDepthMaterial | null;
1355
+ passCleanups.push(material?.isMeshDepthMaterial
1356
+ ? this.beforeDepthRender?.(args[2], material) : undefined);
1357
+ };
1358
+ this.scene.onAfterRender = (...args) => {
1359
+ try { after.apply(this.scene, args); }
1360
+ finally { passCleanups.pop()?.(); }
1361
+ };
1343
1362
  try {
1344
1363
  this.boneSelectionHighlight?.update();
1345
1364
  const camera = this.camera();
@@ -1386,7 +1405,10 @@ export class Object3DDocumentSession {
1386
1405
  }
1387
1406
  this.shading.render(this.scene, mode, () => renderSolid(camera), isEditorViewportShadingTarget);
1388
1407
  } finally {
1389
- finishDraw?.();
1408
+ this.scene.onBeforeRender = before;
1409
+ this.scene.onAfterRender = after;
1410
+ try { while (passCleanups.length) passCleanups.pop()?.(); }
1411
+ finally { finishDraw?.(); }
1390
1412
  }
1391
1413
  }
1392
1414
 
@@ -1909,7 +1909,7 @@ export function Object3DDocumentViewport({
1909
1909
  const mode = documentSession.presentation().mode;
1910
1910
  const navigation = interactive && ['solid', 'preview', 'clay', 'unlit', 'matcap'].includes(mode);
1911
1911
  return source.prepareDraw?.(documentSession.camera(), {interactive: navigation, height: renderer.domElement.height, multiDraw: renderer.extensions.has('WEBGL_multi_draw')});
1912
- });
1912
+ }, (camera, material) => source.prepareDepthDraw?.(camera, material));
1913
1913
  // This loop draws the compass and every other overlay pass over the
1914
1914
  // document's own render, so it — and only it — can serve the chrome
1915
1915
  // door a frame that matches the screen.
@@ -20,6 +20,7 @@ import type {
20
20
  ColorRepresentation,
21
21
  Group,
22
22
  Intersection,
23
+ MeshDepthMaterial,
23
24
  Object3D,
24
25
  Ray,
25
26
  Scene,
@@ -58,6 +59,9 @@ export interface ToolObject3DPreviewSource {
58
59
  * Interactive draws may use disposable navigation geometry; omitted/false
59
60
  * always means full detail (captures and default frame-cost readings). */
60
61
  prepareDraw?(camera: Camera, options?: {interactive: boolean; height: number; multiDraw?: boolean}): void | (() => void);
62
+ /** Optional pass-local depth draws. The host restores them before the next
63
+ * pass, including after a render error. Authored objects remain authoritative. */
64
+ prepareDepthDraw?(camera: Camera, material: MeshDepthMaterial): void | (() => void);
61
65
  /**
62
66
  * EVERY CHANGE TO WHAT THE SOURCE DRAWS, announced: the host calls
63
67
  * `listener` whenever the source's graph, materials, textures or poses may