@deepblend/dsh-blender-host 0.3.9 → 0.5.0

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.
@@ -1,4 +1,5 @@
1
1
  /** Fixed asset preview scenes, compiled in batch mode outside project revisions. */
2
+ import { assertRuntimeSceneFeatures } from './runtime-scene-features.js'
2
3
  import { copyFileSync, existsSync, writeFileSync } from 'node:fs'
3
4
  import { join } from 'node:path'
4
5
  import { randomUUID } from 'node:crypto'
@@ -100,6 +101,8 @@ export async function renderAssetPreview({ runtime, asset, directory, maxMeshPol
100
101
  'The isolated preview scene is invalid.', { detail: { errors: checked.errors } })
101
102
  const compiled = compileSceneSpec(scene).spec
102
103
  writeFileSync(sceneSpecPath, JSON.stringify(compiled))
104
+ const featureCheck = assertRuntimeSceneFeatures(runtime, compiled, { signal })
105
+ if (featureCheck) await featureCheck
103
106
  const result = await runtime.compileScene({ sceneSpecPath, profile: 'preview', projectRoot: directory,
104
107
  jobId: `asset-compile-${randomUUID()}`, session: false, signal,
105
108
  onWorkingDirectory: info => { copyFileSync(join(info.directory, 'result.blend'), checkpointPath) } })
@@ -1,4 +1,5 @@
1
1
  /** Isolated inspection renders. Successful tasks are published with one directory rename. */
2
+ import { assertRuntimeSceneFeatures } from './runtime-scene-features.js'
2
3
  import { createReadStream, copyFileSync, existsSync, mkdirSync, readdirSync, renameSync, writeFileSync } from 'node:fs'
3
4
  import { dirname, join } from 'node:path'
4
5
  import { randomUUID } from 'node:crypto'
@@ -186,6 +187,8 @@ export async function renderDiagnostic(host, request) {
186
187
  }
187
188
  const sceneSpecPath = join(compileRoot, 'scene-spec.json'), checkpointPath = join(compileRoot, 'derived.blend')
188
189
  writeJsonAtomic(sceneSpecPath, scene)
190
+ const featureCheck = assertRuntimeSceneFeatures(runtime, scene, { signal })
191
+ if (featureCheck) await featureCheck
189
192
  const compiled = await runtime.compileScene({ sceneSpecPath, projectRoot: compileRoot, profile: 'preview',
190
193
  jobId: `${jobId}-compile`, session: false, signal,
191
194
  onWorkingDirectory: info => copyFileSync(join(info.directory, 'result.blend'), checkpointPath) })
package/lib/index.js CHANGED
@@ -25,6 +25,7 @@
25
25
  * Plane: Host composition
26
26
  */
27
27
 
28
+ import { assertRuntimeSceneFeatures } from './runtime-scene-features.js'
28
29
  import { Service } from '@deepseek-ai/cordis'
29
30
  import z from '@deepseek-ai/schemastery'
30
31
 
@@ -35,6 +36,7 @@ import {
35
36
  BlenderError,
36
37
  BlenderErrorCode,
37
38
  CREATION_REQUEST_VERSION,
39
+ CAMERA_UPDATE_FIELDS,
38
40
  BlenderWarningCode,
39
41
  SCENE_PATCH_VERSION,
40
42
  buildViewPlan,
@@ -626,6 +628,7 @@ export default class BlenderStudio extends Service {
626
628
  }
627
629
 
628
630
  get creationRequestProtocol() { return CREATION_REQUEST_VERSION }
631
+ get cameraTargetResetSupported() { return CAMERA_UPDATE_FIELDS.includes('clearTarget') }
629
632
 
630
633
  async _createProject(request, creationRequest) {
631
634
  const source = request.recipe ? this.recipes.instantiate(request.recipe) : null
@@ -1185,6 +1188,8 @@ export default class BlenderStudio extends Service {
1185
1188
  */
1186
1189
  async compileRevisionForRender(input) {
1187
1190
  const { projectId, revision, spec } = input
1191
+ const featureCheck = assertRuntimeSceneFeatures(this.runtime, spec, { signal: input.signal })
1192
+ if (featureCheck) await featureCheck
1188
1193
  const scratch = resolveInside(
1189
1194
  this.store.workspaceRoot,
1190
1195
  join(this.store.workspaceRoot, 'tmp', `render-${revision}-${Date.now().toString(36)}`),
@@ -41,6 +41,7 @@
41
41
  * Plane: Host composition
42
42
  */
43
43
 
44
+ import { assertRuntimeSceneFeatures } from './runtime-scene-features.js'
44
45
  import { existsSync, mkdirSync, readdirSync, renameSync, statSync } from 'node:fs'
45
46
  import { randomUUID } from 'node:crypto'
46
47
  import { join } from 'node:path'
@@ -570,6 +571,8 @@ export class RevisionTransaction {
570
571
  const checkpointStaging = join(staging, 'scene.blend')
571
572
 
572
573
  try {
574
+ const featureCheck = assertRuntimeSceneFeatures(this.runtime, plan.spec, { signal: plan.signal })
575
+ if (featureCheck) await featureCheck
573
576
  const run = await this.runtime.compileScene({
574
577
  sceneSpecPath: specPath,
575
578
  profile: plan.spec.renderProfiles?.preview === undefined ? undefined : 'preview',
@@ -0,0 +1,21 @@
1
+ import { BlenderError, BlenderErrorCode, requiredSceneFeatures } from '@deepblend/dsh-blender-contracts'
2
+
3
+ /** Old runtimes must not silently compile an axis-sized box as their scalar default. */
4
+ export function assertRuntimeSceneFeatures(runtime, spec, { signal } = {}) {
5
+ const required = requiredSceneFeatures(spec)
6
+ if (required.length === 0) return
7
+ return (async () => {
8
+ signal?.throwIfAborted()
9
+ const capabilities = typeof runtime?.getCapabilities === 'function'
10
+ ? await runtime.getCapabilities({ signal }) : null
11
+ signal?.throwIfAborted()
12
+ if (capabilities?.installed === false) {
13
+ throw new BlenderError(BlenderErrorCode.NOT_FOUND, 'Blender is unavailable for this scene.')
14
+ }
15
+ const supported = Array.isArray(capabilities?.sceneFeatures) ? capabilities.sceneFeatures : []
16
+ const missing = required.filter(feature => !supported.includes(feature))
17
+ if (missing.length) throw new BlenderError(BlenderErrorCode.SCENE_FEATURE_UNSUPPORTED,
18
+ `The runtime does not support ${missing.join(', ')}. Update the runtime before compiling this scene.`,
19
+ { detail: { required, supported, missing } })
20
+ })()
21
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepblend/dsh-blender-host",
3
- "version": "0.3.9",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "description": "DeepBlend Host service: the blenderStudio business facade over the BlenderRuntime seam.",
6
6
  "main": "lib/index.js",
@@ -20,7 +20,7 @@
20
20
  "./package.json": "./package.json"
21
21
  },
22
22
  "dependencies": {
23
- "@deepblend/dsh-blender-contracts": "0.3.9",
23
+ "@deepblend/dsh-blender-contracts": "0.5.0",
24
24
  "sharp": "0.35.5"
25
25
  },
26
26
  "license": "MIT",