dsh-preview-blender 0.0.0-stage → 0.1.1

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/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 — 2026-10-20
4
+
5
+ First release.
6
+
7
+ - Register a document-preview renderer for `.blend` files in the DSH right Sidebar: clicking a scene opens an interactive 3D viewport instead of the binary-file empty state.
8
+ - Host half: authenticated `GET|HEAD /api/preview/blender` route that exports one GLB plus a scene JSON per file version with `blender --background`, keyed by real path, size, mtime, export recipe and the modifier setting, cached under `~/.dsh/cache/preview-blender` and pruned to `cacheEntries`.
9
+ - Browser half: dependency-free WebGL glTF 2.0 viewer (orbit / pan / zoom / double-click reset / wireframe / auto-rotate / contact shadow / axis triad) and a scene panel with per-object triangle counts, millimetre bounding boxes, material swatches, units and export facts.
10
+ - Configuration: `enabled`, `routePath`, `extensions`, `blenderPath`, `cacheDir`, `timeoutMs`, `maxBytes`, `applyModifiers`, `cacheEntries`.
11
+ - Blender discovery: `DSH_BLENDER`, `BLENDER_PATH`, `PATH`, Steam libraries, `Blender Foundation` installs; a missing binary produces an actionable `BLENDER_MISSING` error instead of a blank panel.
12
+ - Verified on Blender 5.2.2 LTS / DSH Desktop 0.2.1-rc.2 with a real scene (22,960 triangles): 27 unit/adapter tests, cold conversion 2.1 s, warm 3 ms, headless browser e2e ready state with 16% non-background canvas pixels.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 439436269-ctrl
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,90 @@
1
- # Temporary Holding Version
1
+ # dsh-preview-blender
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Preview Blender **`.blend`** files inside [DeepSeek Harness](https://github.com/deepseek-ai): the right-Sidebar document preview turns the scene into an interactive 3D viewport (orbit / zoom / wireframe) with a scene-information panel, instead of the built-in “binary file, no preview” empty state.
4
+
5
+ ![The preview inside the DSH right Sidebar](https://raw.githubusercontent.com/439436269-ctrl/dsh-preview-blender/main/docs/preview-blender.png)
6
+
7
+ ## What it does
8
+
9
+ - Registers a document-preview renderer for `.blend` files, so clicking one in **Workspace files** opens it in the right Sidebar.
10
+ - Runs `blender --background` once per file version to export a **GLB** plus a scene JSON (objects, triangles, materials, real-world size in mm, units, cameras, lights, collections).
11
+ - Draws the GLB with a small **dependency-free WebGL viewer** written for this plugin: orbit, pan, wheel zoom, double-click reset, wireframe mode, auto-rotate, a soft contact shadow and an axis triad. No CDN, no three.js.
12
+ - Caches conversions under `~/.dsh/cache/preview-blender`; the second open is instant (a few milliseconds).
13
+ - Shows the scene facts that matter for CAD/3D-printing work: per-object triangle counts and bounding-box sizes in millimetres, material swatches, scene units.
14
+
15
+ ## Requirements
16
+
17
+ - DeepSeek Harness 0.2.x (declared compatible with `0.2.0-rc.2` and `0.2.1-rc.2`).
18
+ - **Blender 3.6 / 4.x / 5.x** installed. The plugin auto-detects `DSH_BLENDER`, `BLENDER_PATH`, `blender` on `PATH`, the Steam library, and `C:\Program Files\Blender Foundation\Blender*`. Set `blenderPath` if your install lives elsewhere.
19
+ - A browser/GPU with WebGL (the DSH desktop app always has it).
20
+
21
+ ## Install
22
+
23
+ ```sh
24
+ # into a normal (non-desktop) profile
25
+ dsh plugin --profile <profile> add dsh-preview-blender
26
+
27
+ # the desktop profile is owned by the Electron app; add it there through the
28
+ # plugin manager UI, or compose it manually and restart the app
29
+ ```
30
+
31
+ The package ships a `cordis.patch.yml`, so installation adds the plugin row automatically. Restart DSH after installing.
32
+
33
+ ## Configuration
34
+
35
+ Settings → Plugins → **Blender preview** (namespace `preview-blender`):
36
+
37
+ | Key | Default | Meaning |
38
+ |---|---|---|
39
+ | `enabled` | `true` | Register the renderer and the conversion route. |
40
+ | `routePath` | `/api/preview/blender` | Authenticated conversion route. Must stay under `/api`; otherwise the authenticated fence is bypassed, so it falls back to the default. |
41
+ | `extensions` | `["blend"]` | Suffixes that open in the 3D preview. |
42
+ | `blenderPath` | `""` (auto) | Absolute path of `blender.exe` / `blender`. |
43
+ | `cacheDir` | `""` → `~/.dsh/cache/preview-blender` | Where exported GLB files and scene JSON live. |
44
+ | `timeoutMs` | `180000` | Wall-clock ceiling for one cold conversion. |
45
+ | `maxBytes` | `1073741824` | Largest `.blend` converted (1 GiB). |
46
+ | `applyModifiers` | `true` | Apply modifiers during export, so the preview matches what Blender renders. |
47
+ | `cacheEntries` | `24` | Cached conversions kept on disk before the oldest are pruned. |
48
+
49
+ ## How it works
50
+
51
+ ```
52
+ Workspace file click
53
+ │
54
+ ▼
55
+ document preview body (lib/client.js)
56
+ │ GET /api/preview/blender?path=…&kind=info (scene JSON)
57
+ │ GET /api/preview/blender?path=…&kind=glb (model bytes)
58
+ ▼
59
+ Host half (lib/index.js, lib/route.js)
60
+ │ cache key = sha1(realpath, size, mtime, recipe, modifiers)
61
+ ▼
62
+ lib/blender.js ── spawn blender --background --python lib/scene.py
63
+ │ → model.glb + scene.json (+ meta.json)
64
+ ▼
65
+ ~/.dsh/cache/preview-blender/<key>/
66
+ ```
67
+
68
+ - `lib/scene.py` exports with `export_apply`, `use_visible`, **Y-up**, no cameras/lights, and writes the scene description (world-space AABBs through the evaluated depsgraph, Principled base colours converted to sRGB swatches).
69
+ - The route lives under `/api`, so the connection service authenticates every request (Host/Origin fence + session cookie). Arbitrary local files are not exposed.
70
+ - The viewer is a hand-written glTF 2.0 subset renderer (POSITION + NORMAL, indexed triangles, PBR factors, node TRS/matrix). Textures, skinning and animation are out of scope; the Host only exports still scenes.
71
+
72
+ ## Development
73
+
74
+ ```
75
+ dev/client-body.js client UI (single CJS factory for the DSH module loader)
76
+ dev/viewer.js the WebGL renderer, spliced into the bundle at build time
77
+ scripts/build-client.mjs builds lib/client.js from the two files
78
+ scripts/e2e-browser.mjs Playwright end-to-end against a temporary DSH host
79
+ scripts/live-selftest.mjs cold/warm/concurrent conversion against a real .blend
80
+ node --test test/*.test.js
81
+ ```
82
+
83
+ `lib/client.js` is generated — edit the files under `dev/` and rebuild. The DSH client loader hands the bundle a `require` limited to the platform seed modules, so the package cannot pull a renderer dependency at runtime; the single generated file is the intended shape.
84
+
85
+ ## Notes and limits
86
+
87
+ - A cold conversion takes roughly 2–10 s for a small scene (Blender startup dominates); it is cached per file version, so rotating/zooming never re-runs Blender.
88
+ - Very large scenes (millions of triangles) export slowly and may exceed `timeoutMs`.
89
+ - Textures are not shown in the viewport (base colours only); the Blender renders next to the file are still the reference.
90
+ - Nothing is uploaded: Blender runs locally and the GLB stays in the local cache.
package/README.zh.md ADDED
@@ -0,0 +1,86 @@
1
+ # dsh-preview-blender
2
+
3
+ 在 DeepSeek Harness 的右侧栏文档预览里直接打开 Blender **`.blend`** 文件:用 Blender 后台导出一份 GLB,再用插件自带的 WebGL 视口做可旋转、可缩放的 3D 预览,并列出场景信息。
4
+
5
+ ![右侧栏里的预览](https://raw.githubusercontent.com/439436269-ctrl/dsh-preview-blender/main/docs/preview-blender.png)
6
+
7
+ ## 它做什么
8
+
9
+ - 给 `.blend` 注册文档预览渲染器:在工作区文件树里点一下,右侧栏就打开 3D 预览,而不是「二进制文件无法预览」。
10
+ - 每个文件版本只跑一次 `blender --background`,导出 **GLB** + 场景 JSON(对象、三角面、材质、真实尺寸 mm、单位、相机、灯光、集合)。
11
+ - 插件自带一个零依赖的 **WebGL 查看器**:拖动旋转、右键平移、滚轮缩放、双击复位、线框模式、自动旋转、接触阴影、坐标轴。不依赖 three.js,不走 CDN。
12
+ - 转换结果缓存在 `~/.dsh/cache/preview-blender`,第二次打开是毫秒级。
13
+ - 面板直接给建模/打印关心的数:每个对象的三角面数与包围盒尺寸(mm)、材质色块、场景单位。
14
+
15
+ ## 依赖
16
+
17
+ - DeepSeek Harness 0.2.x(声明兼容 `0.2.0-rc.2` / `0.2.1-rc.2`)。
18
+ - **Blender 3.6 / 4.x / 5.x**。会自动找 `DSH_BLENDER`、`BLENDER_PATH`、`PATH` 里的 `blender`、Steam 库、`C:\Program Files\Blender Foundation\Blender*`;装在别处就填 `blenderPath`。
19
+ - 浏览器/显卡支持 WebGL(桌面版 DSH 天然满足)。
20
+
21
+ ## 安装
22
+
23
+ ```sh
24
+ dsh plugin --profile <profile> add dsh-preview-blender
25
+ ```
26
+
27
+ 桌面版(desktop profile)由 Electron 应用管着,用设置页的插件管理器安装,或手工装入后重启应用。包内自带 `cordis.patch.yml`,装好即自动挂载。**装完重启 DSH。**
28
+
29
+ ## 配置
30
+
31
+ 设置 → 插件 → **Blender preview**(命名空间 `preview-blender`):
32
+
33
+ | 键 | 默认 | 含义 |
34
+ |---|---|---|
35
+ | `enabled` | `true` | 是否注册渲染器与转换路由。 |
36
+ | `routePath` | `/api/preview/blender` | 带鉴权的转换路由;必须留在 `/api` 下,否则回落到默认值(防止裸路由读本地文件)。 |
37
+ | `extensions` | `["blend"]` | 走 3D 预览的后缀。 |
38
+ | `blenderPath` | `""`(自动) | `blender.exe` / `blender` 的绝对路径。 |
39
+ | `cacheDir` | `""` → `~/.dsh/cache/preview-blender` | GLB 与场景 JSON 的缓存目录。 |
40
+ | `timeoutMs` | `180000` | 单次冷转换的墙钟上限。 |
41
+ | `maxBytes` | `1073741824` | 允许转换的最大 `.blend`(1 GiB)。 |
42
+ | `applyModifiers` | `true` | 导出时应用修改器,预览与 Blender 渲染一致。 |
43
+ | `cacheEntries` | `24` | 磁盘上保留多少个缓存条目,超出按最旧淘汰。 |
44
+
45
+ ## 工作原理
46
+
47
+ ```
48
+ 点击工作区里的 .blend
49
+ │
50
+ ▼
51
+ 文档预览 body(lib/client.js)
52
+ │ GET /api/preview/blender?path=…&kind=info (场景 JSON)
53
+ │ GET /api/preview/blender?path=…&kind=glb (模型字节)
54
+ ▼
55
+ Host 半(lib/index.js、lib/route.js)
56
+ │ 缓存键 = sha1(realpath, size, mtime, recipe, modifiers)
57
+ ▼
58
+ lib/blender.js ── spawn blender --background --python lib/scene.py
59
+ │ → model.glb + scene.json(+ meta.json)
60
+ ▼
61
+ ~/.dsh/cache/preview-blender/<key>/
62
+ ```
63
+
64
+ - `lib/scene.py` 以 `export_apply`、`use_visible`、**Y-up** 导出,不带相机/灯光;场景描述里的世界包围盒走 evaluated depsgraph(含修改器),材质底色从线性色转成 sRGB 色块。
65
+ - 路由挂在 `/api` 下,请求先经过 connection 服务的鉴权(Host/Origin + 会话 cookie),不会把任意本地文件暴露成裸接口。
66
+ - 查看器是手写的 glTF 2.0 子集渲染(POSITION + NORMAL、索引三角形、PBR 因子、节点 TRS/矩阵)。纹理、蒙皮、动画不在范围内——Host 只导出静帧场景。
67
+
68
+ ## 开发
69
+
70
+ ```
71
+ dev/client-body.js 客户端 UI(DSH 模块加载器要求的单个 CJS 工厂)
72
+ dev/viewer.js WebGL 渲染器,构建时拼进 bundle
73
+ scripts/build-client.mjs 由上面两个文件生成 lib/client.js
74
+ scripts/e2e-browser.mjs 针对临时 DSH 实例的 Playwright 端到端
75
+ scripts/live-selftest.mjs 真实 .blend 的冷/热/并发转换自检
76
+ node --test test/*.test.js
77
+ ```
78
+
79
+ `lib/client.js` 是生成物——改 `dev/` 下的文件后重新构建。DSH 客户端加载器只给 bundle 一枚受限的 `require`(平台种子模块),不能在运行时拉 three.js,所以「单文件产物」是刻意设计。
80
+
81
+ ## 已知边界
82
+
83
+ - 冷转换小场景约 2–10 秒(Blender 启动为主),之后按文件版本命中缓存,旋转/缩放不会重跑 Blender。
84
+ - 超大场景(数百万三角面)导出慢,可能超过 `timeoutMs`。
85
+ - 视口只显示底色,不显示纹理;纹理效果仍以 Blender 渲染图为准。
86
+ - 不上传任何文件:Blender 在本机跑,GLB 只留在本地缓存。
package/VERIFY.md ADDED
@@ -0,0 +1,159 @@
1
+ # Verification record — dsh-preview-blender 0.1.0
2
+
3
+ Date: 2026-10-20. Machine: Windows 11, DeepSeek Harness Desktop **0.2.1-rc.2**
4
+ (`<DSH install>`), **Blender 5.2.2 LTS**
5
+ (`<Blender install>\blender.exe`), Node 24.22.0.
6
+ Scene under test: `<workspace>\plate-rack-base\out\plate_rack_base.blend`
7
+ (280,645 bytes, 5 mesh objects, 22,960 triangles, 3 materials, 2 collections).
8
+
9
+ ## L1 — unit / adapter tests
10
+
11
+ ```
12
+ node --test test/*.test.js
13
+ # tests 27 pass 27 fail 0
14
+ ```
15
+
16
+ | file | what it proves |
17
+ |---|---|
18
+ | `test/config.test.js` | defaults; route forced under `/api/`; suffix normalization; numeric clamps; `~` expansion; custom cache dir |
19
+ | `test/blender.test.js` | candidate order (config → env → PATH → platform installs); cache-key sensitivity to size / mtime / modifiers; `runProcess` output + exit code + timeout; missing scene refused before spawning; a broken Blender run surfaces `BLEND_EXPORT_FAILED` with the log tail; a complete cache entry is returned without Blender; `BLENDER_MISSING` hint names `blenderPath` and the probed locations |
20
+ | `test/route.test.js` | info JSON (scene + cache facts + Blender version); GLB bytes with `model/gltf-binary` and exact length; HEAD without a body; `path`/`kind`/suffix validation before any conversion; 404 for a missing file; `BLENDER_MISSING` → 503 with the hint |
21
+ | `test/adapter.test.js` | the Host entry imports with a stub schemastery; `apply()` registers `GET|HEAD /api/preview/blender`, publishes `__DSH_PREVIEW_BLENDER_CONFIG__`, disposes both effects; `enabled: false` mounts nothing; the manifest ships `lib/**/*.py` and the client export |
22
+ | `test/client.test.js` | the bundle evaluates in a browser-shaped sandbox, registers id `dsh-preview-blender`, exports `apply`/`inject`/`__createViewer`; `apply()` registers one renderer (`.blend`, extension priority, renderer-owned loading), one body slot and both dictionaries; the injected route path is honoured, and a missing injection falls back to `/api/preview/blender` |
23
+
24
+ ## L2 — live conversion (`scripts/live-selftest.mjs`)
25
+
26
+ ```
27
+ file: <workspace>/plate-rack-base/out/plate_rack_base.blend
28
+ cache: %TEMP%\blend-selftest-cache-*
29
+
30
+ PASS cold conversion produced a GLB 1050200 bytes
31
+ PASS cold conversion reports a Blender version Blender 5.2.2 LTS
32
+ PASS scene JSON has objects and triangles 5 objects / 22960 tris
33
+ PASS scene bounds are in millimetres 322 × 144.809 × 182.555
34
+ PASS cold conversion was not a cache hit 1325 ms
35
+ PASS second call is a cache hit
36
+ PASS cache hit is much faster than the cold run 3 ms
37
+ PASS both calls share one cache key fcff667d0558178e6981ed49
38
+ PASS concurrent requests share one in-flight job 1 job(s)
39
+ PASS concurrent callers get the same artifact
40
+ PASS cache stays within cacheEntries 1 entries
41
+
42
+ ALL PASS
43
+ ```
44
+
45
+ The exported GLB is 1,050,200 bytes; the scene JSON reports
46
+ `Base_Full` 322 × 129 × 16 mm (9,092 tris), `Half_L` / `Half_R`
47
+ 161 × 129 × 16 mm (4,546 tris each), `Plate` 196 × 126.7 × 157.4 mm,
48
+ `Rack_Proxy` 306 × 113 × 123 mm; units `MILLIMETERS (1000 mm/unit)`.
49
+
50
+ ## L3 — HTTP route on a real DSH host
51
+
52
+ Temporary profile `blendverify` (web template + the packed tarball),
53
+ `dsh --profile blendverify --no-open --port 0`, authenticated with the
54
+ printed `?token=` cookie:
55
+
56
+ ```
57
+ index: 200 len=35270
58
+ boot has plugin: True
59
+ __DSH_PREVIEW_BLENDER_CONFIG__ injected: True
60
+ info: 200 in 1.4s len=2415
61
+ scene: 22960 tris, blender=Blender 5.2.2 LTS, cached=False, glb=1050200
62
+ glb: 200 bytes=1050200 type=model/gltf-binary
63
+ ```
64
+
65
+ ## L4 — headless browser end-to-end (`scripts/e2e-browser.mjs`)
66
+
67
+ Flow: open the app with the token, start a conversation, open the right
68
+ Sidebar, Workspace files, walk `codes → plate-rack-base → out`, open
69
+ `plate_rack_base.blend`, wait for the preview, sample canvas pixels, toggle
70
+ wireframe and the info panel.
71
+
72
+ ```
73
+ tree segment codes: opened
74
+ tree segment plate-rack-base: opened
75
+ tree segment out: opened
76
+ {
77
+ "state": "ready",
78
+ "triangles": "22960",
79
+ "canvasSize": { "width": 719, "height": 489 },
80
+ "pixels": { "lit": 8195, "total": 50228, "ratio": 0.1632 },
81
+ "objectNames": ["Base_Full", "Half_L", "Half_R", "Plate", "Rack_Proxy"],
82
+ "panelLen": 341,
83
+ "panelHasSize": true,
84
+ "panelHidden": "false",
85
+ "failure": "",
86
+ "errors": []
87
+ }
88
+ ```
89
+
90
+ The renderer-owned loading flag resolved (`data-blend-state="ready"`), the
91
+ canvas is 719 × 489 device pixels, 16.3% of the sampled pixels are brighter
92
+ than the background (the model is actually drawn, not a blank canvas), all
93
+ five mesh objects appear in the panel, the panel shows `322 … mm`, there are
94
+ no console errors, and the wireframe toggle changes the frame (screenshot).
95
+
96
+ Screenshots: `scripts/shots/03-preview.png` (solid), `04-wireframe.png`
97
+ (wireframe), `02-sidebar.png` (file tree), and the user-facing copy
98
+ `docs/preview-blender.png`.
99
+
100
+ ## Desktop profile installation
101
+
102
+ The running app owns its profile, so `dsh plugin --profile desktop …` is
103
+ refused. Installed the same way the earlier media-preview plugin was:
104
+
105
+ 1. Backed up `package.json`, `pnpm-lock.yaml`, `cordis.patch.yml`
106
+ (`*.bak-blend-20261020-232354`).
107
+ 2. Added `"dsh-preview-blender": "file:<repo>/dsh-preview-blender-0.1.0.tgz"`
108
+ and appended `dsh-preview-blender` to `dsh.profile.bundles`.
109
+ 3. `node ~/.dsh/dsh-runtimes/dsh-primary-runtime/dependencies/pnpm/bin/pnpm.cjs install --dir ~/.dsh/profiles/desktop`
110
+ → `+ dsh-preview-blender 0.1.0`, done in 3.7 s.
111
+ 4. Composition proven on a copy of the desktop profile with a junctioned
112
+ `node_modules`: `--dump-config` contains one `id: preview-blender` row with
113
+ the shipped config; `--dump-config-schema` reports `status: schema`
114
+ (Config imported, no `Cannot find package`), then the copy was removed
115
+ (junction unlinked with `rmdir`, desktop `node_modules` untouched).
116
+ 5. Installed `lib/client.js` hash equals the built file
117
+ `19BDAC036C53637FA857EA638651FD5F82FBB8F5F9B83A787D63D012638A3F6C`.
118
+
119
+ **Not yet exercised: the restarted desktop app.** The desktop host composes
120
+ its plugin tree at boot, so the new row activates on the next launch. The
121
+ same code and the same client API were exercised end-to-end on the 0.2.0
122
+ web host above; 0.2.1-rc.2 is the release media-preview 0.1.2 already runs
123
+ on, so the document-preview surface is unchanged.
124
+
125
+ Side effect to know about: `pnpm install` also refreshed an unrelated
126
+ satisfied range, `@vfvrpq/dsh-pinned-sessions` 0.4.0 → 0.4.1 (the profile
127
+ already excludes that version from the release-age gate).
128
+
129
+ ## Pitfalls found
130
+
131
+ | Symptom | Root cause | Fix |
132
+ |---|---|---|
133
+ | `preview-blender (dsh-preview-blender): failed to import` with no detail; `--dump-config-schema` says `Cannot find package '@deepseek-ai/schemastery' imported from <repo>\lib\schema.js` | `pnpm add <directory>` installs a **link**; Node resolves `@deepseek-ai/schemastery` from the real package path (`<workspace>\…`), which never reaches `~/.dsh/profiles/node_modules` | install from a packed tarball (`pnpm pack` → `dsh plugin add <tgz>`); the copy lives under the profile and resolves the shared `profiles/node_modules` |
134
+ | Preview shows 「这个浏览器/显卡组合不支持 WebGL」 while the canvas is 300×150 | the viewer was created in a mount effect that ran while the component still rendered the “loading” branch (no canvas); it never retried when the canvas appeared | create the viewer from the canvas `ref` callback, dispose on `null`; the model fetch then finds a live viewer |
135
+ | Wireframe toggle changes the button state but not the picture | the LINES pass drew with the triangle index buffer bound instead of the generated edge buffer | bind `primitive.lineIndices` for the edge pass; edges replace the surface (a 68k-edge overlay on top of the solid turned to mush) |
136
+ | Blender reports success but no GLB appears | the glTF exporter rewrites the filepath to end in `.glb`, so `model.glb.part` became `model.glb.part.glb` | write `model.part.glb` and rename to `model.glb` |
137
+
138
+ ## Release — 0.1.0 (2026-10-21)
139
+
140
+ | Item | Value |
141
+ |---|---|
142
+ | GitHub | https://github.com/439436269-ctrl/dsh-preview-blender (public, topics `dsh-plugin` + `blender`/`gltf`/`preview`/`3d`) |
143
+ | Branch / tag | `main` at `71bb02e` (API-pushed; local `HEAD` is content-equivalent), tag `v0.1.0` → `71bb02e` |
144
+ | CI | `ci` workflow **success** on `71bb02e` (Node 22 + 24) |
145
+ | npm | `dsh-preview-blender@0.1.0`, `dist-tags.latest = 0.1.0` |
146
+ | Published | 2026-10-21T02:40:51.801Z |
147
+ | shasum / integrity | `4efc8df3aeb3fd1cf72dba88eb4a250d75a0d870` / `sha512-8BnUHbg/PFoX6v8uMAxTl+75US3Rs7KmZItBhpAF4GufiJPUOMD4znP9bnyZOBXMIGtle/GN58cK0XBbgwduUQ==` |
148
+ | Tarball | 14 files, 137,744 B unpacked |
149
+ | Install | `dsh plugin --profile <profile> add dsh-preview-blender@0.1.0` |
150
+
151
+ Artifact read-back:
152
+
153
+ - `GET /-/package/dsh-preview-blender/dist-tags` → `{"latest":"0.1.0"}`; both `GET /dsh-preview-blender/0.1.0` and `/latest` → 200.
154
+ - Downloaded tarball sha1 == `dist.shasum`; sha512 integrity verified.
155
+ - 13 of 14 files byte-identical to the source tree; the remaining `package.json` differs only in bytes (npm repacks it) while its parsed JSON is semantically equal. `lib/client.js` sha256 `19BDAC036C53637FA857EA638651FD5F82FBB8F5F9B83A787D63D012638A3F6C` matches the built file.
156
+ - Desktop profile dependency switched from the local tarball to `dsh-preview-blender@0.1.0` (explicit version bypasses the 24 h release-age gate; pnpm recorded it in `minimumReleaseAgeExclude`). The installed `lib/client.js` hash still matches the build.
157
+
158
+ Push note: `github.com:443` reset connections from this network (35 s timeout on `git ls-remote`), so the empty repository was seeded through the Contents API and the tree was pushed with the Git Data API. The server tree equals local `HEAD^{tree}` (`4a1b0c6`); the server commit SHA differs by design (different committer/time), so `git status` shows the local branch ahead until `git fetch` works again.
159
+
@@ -0,0 +1,31 @@
1
+ # dsh-preview-blender bundle patch: one plugin row.
2
+ #
3
+ # A patch replaces the targeted row's whole `config`, so a profile that wants to
4
+ # override one key must restate the others it cares about. Every key below also
5
+ # has a code-side default in lib/config.js, so this file stays valid even when a
6
+ # patch-side helper is unavailable.
7
+ #
8
+ # `routePath` must stay under /api: the connection service authenticates every
9
+ # /api request (Host/Origin fence + browser session cookie) before the route
10
+ # runs, which is what keeps an arbitrary local file from being readable by a
11
+ # cross-site page.
12
+
13
+ - insert:
14
+ - id: preview-blender
15
+ name: dsh-preview-blender
16
+ config:
17
+ enabled: true
18
+ routePath: /api/preview/blender
19
+ extensions:
20
+ - blend
21
+ # Empty means "detect": DSH_BLENDER / BLENDER_PATH, then PATH, then the
22
+ # usual Steam and Blender Foundation install locations.
23
+ blenderPath: ""
24
+ # Empty means ~/.dsh/cache/preview-blender.
25
+ cacheDir: ""
26
+ # A cold conversion runs one Blender process; a 300 MB scene takes
27
+ # tens of seconds, so the ceiling is generous.
28
+ timeoutMs: 180000
29
+ maxBytes: 1073741824
30
+ applyModifiers: true
31
+ cacheEntries: 24