partforge 0.52.0 → 0.53.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.
- package/docs/AUTHORING-PARTS.md +8 -3
- package/package.json +1 -1
- package/src/framework/mount.js +3 -1
- package/src/framework/viewer.js +40 -4
package/docs/AUTHORING-PARTS.md
CHANGED
|
@@ -1250,9 +1250,14 @@ instead of (or in addition to) the built-in `#part` bar:
|
|
|
1250
1250
|
`viewName` rendered offscreen (falling back to the resolved default view — see
|
|
1251
1251
|
`resolveDefaultView` / `default-view.js` — when `viewName` is omitted or names a view the
|
|
1252
1252
|
part doesn't declare). Never disturbs the active tab, the live camera, or the on-screen
|
|
1253
|
-
scene; `opts` forwards to the underlying render (size, quality, angle).
|
|
1254
|
-
failure rather than throwing (a build error, a part with no sub-parts
|
|
1255
|
-
disposed runtime).
|
|
1253
|
+
scene; `opts` forwards to the underlying render (size, quality, angle, background).
|
|
1254
|
+
Resolves `null` on failure rather than throwing (a build error, a part with no sub-parts
|
|
1255
|
+
in that view, a disposed runtime). The render happens in a throwaway scene, so it takes
|
|
1256
|
+
no colour from the viewer's light/dark theme: it gets a fixed neutral grey, on the
|
|
1257
|
+
reasoning that a thumbnail is captured once and then displayed under host chrome
|
|
1258
|
+
partforge cannot see. Pass `background` (any `THREE.Color`-compatible value) to choose
|
|
1259
|
+
your own, or `background: null` for no background at all — which clears to opaque black
|
|
1260
|
+
unless the embedder has set a clear colour.
|
|
1256
1261
|
|
|
1257
1262
|
Pass `onViewChange(name)` to `mount()` to be told the active view: it fires once
|
|
1258
1263
|
synchronously during mount with the initial resolved view (before `runtime.ready` settles),
|
package/package.json
CHANGED
package/src/framework/mount.js
CHANGED
|
@@ -644,7 +644,9 @@ export function mount(part, { createWorker, elements = {}, onBuild, onPick, onDo
|
|
|
644
644
|
// renders it in a throwaway scene via viewer.renderMeshPayloads. Never
|
|
645
645
|
// touches the active tab, getView(), or the live scene — best-effort: any
|
|
646
646
|
// failure, including a resolved-null from a worker build failure (4A
|
|
647
|
-
// settles rather than throwing), returns null.
|
|
647
|
+
// settles rather than throwing), returns null. `opts` is spread last, so
|
|
648
|
+
// renderMeshPayloads' own options (including `background`) pass straight
|
|
649
|
+
// through from the caller.
|
|
648
650
|
const captureView = async (viewName, opts = {}) => {
|
|
649
651
|
try {
|
|
650
652
|
const target = (viewName && part.views?.[viewName]) ? viewName : resolveDefaultView(part);
|
package/src/framework/viewer.js
CHANGED
|
@@ -57,6 +57,36 @@ export function captureViewsFromScene(viewNames, { renderer, liveCamera, grid, b
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
// The off-loop thumbnail capture (renderMeshPayloads, behind the handle's
|
|
61
|
+
// captureView) renders a THROWAWAY scene, so it gets no background from the
|
|
62
|
+
// live scene's theme — and before this constant existed it set none at all,
|
|
63
|
+
// which meant every thumbnail came back on the renderer's default opaque
|
|
64
|
+
// black, in light mode as much as dark. One deliberately theme-INDEPENDENT
|
|
65
|
+
// colour is the right answer rather than either THEME entry below: a thumbnail
|
|
66
|
+
// is baked at capture time and displayed later under host chrome this renderer
|
|
67
|
+
// cannot know (partforge-cloud's card grid draws them on both). Near the
|
|
68
|
+
// perceptual midpoint of THEME.light.bg / THEME.dark.bg, so it commits to
|
|
69
|
+
// neither, and clear of both the part material (0x9fb4cc, lighter) and the
|
|
70
|
+
// feature-edge lines (0x1c232d, much darker).
|
|
71
|
+
//
|
|
72
|
+
// The near-ZERO chroma is the part that looks arbitrary and isn't: the default
|
|
73
|
+
// part material is blue-grey, so a blue-grey background of the same value
|
|
74
|
+
// (0x6b7280 was the first try) competes with it and the shaded side of a part
|
|
75
|
+
// half-disappears into the plate. A neutral grey separates by hue as well as
|
|
76
|
+
// value. Judged on real captures of demo.js and hinged-box.js — if this is
|
|
77
|
+
// ever retuned, retune it the same way and not by eye on the hex.
|
|
78
|
+
export const THUMBNAIL_BG = 0x6e6e73;
|
|
79
|
+
|
|
80
|
+
// Resolve renderMeshPayloads' `background` option to what Scene.background
|
|
81
|
+
// wants. Exported for its own sake: renderMeshPayloads needs a GL context and
|
|
82
|
+
// so is untestable directly, and this is the whole of the decision. `null` is
|
|
83
|
+
// a real escape hatch — the pre-existing no-background behaviour, clearing to
|
|
84
|
+
// the renderer's clear colour — so it is passed through rather than treated as
|
|
85
|
+
// "unset"; only `undefined` (an absent option) takes the default.
|
|
86
|
+
export function thumbnailBackground(background = THUMBNAIL_BG) {
|
|
87
|
+
return background === null ? null : new THREE.Color(background);
|
|
88
|
+
}
|
|
89
|
+
|
|
60
90
|
// Render the LIVE camera's current framing offscreen, once, at a caller-chosen
|
|
61
91
|
// resolution — the showcase capture behind the runtime handle's captureCurrent.
|
|
62
92
|
// Same injected-renderer split as captureViewsFromScene so it runs without a GL
|
|
@@ -646,12 +676,18 @@ export function createViewer(container, part) {
|
|
|
646
676
|
// Offscreen render of an arbitrary mesh set (a non-active view), for thumbnails.
|
|
647
677
|
// Assembles a THROWAWAY scene mirroring the live pivot convention, frames it from a
|
|
648
678
|
// canonical angle, renders through the parameterized renderOffscreen, and disposes
|
|
649
|
-
// everything. Never touches the live scene, camera, subMesh, or subCache.
|
|
650
|
-
//
|
|
651
|
-
//
|
|
652
|
-
|
|
679
|
+
// everything. Never touches the live scene, camera, subMesh, or subCache. The scene
|
|
680
|
+
// gets THUMBNAIL_BG unless `background` says otherwise (`null` = no background, the
|
|
681
|
+
// renderer's clear colour). `payloads` is the worker's [{name, positions, normals,
|
|
682
|
+
// indices, …}] array — placement is already baked into shared-frame coords, so
|
|
683
|
+
// meshes are NOT recentred.
|
|
684
|
+
function renderMeshPayloads(payloads, { angle = "iso", size = 640, quality = 0.8, background } = {}) {
|
|
653
685
|
if (disposed) return null; // same guard as captureCurrent/captureCanonicalViews — never touch a torn-down renderer
|
|
654
686
|
const tmpScene = new THREE.Scene();
|
|
687
|
+
// Deliberately the throwaway scene's own background, never the live one's:
|
|
688
|
+
// this must not follow the viewer theme (see THUMBNAIL_BG) and must not
|
|
689
|
+
// reach the live-scene captures, which correctly do follow it.
|
|
690
|
+
tmpScene.background = thumbnailBackground(background);
|
|
655
691
|
const tmpPivot = new THREE.Group();
|
|
656
692
|
tmpPivot.rotation.x = -Math.PI / 2; // model Z (CAD up) -> vertical, same as live pivot
|
|
657
693
|
tmpScene.add(tmpPivot);
|