Add Chromium-only Blender WebEngine parity work

This commit is contained in:
mes123456
2026-08-12 04:47:48 -04:00
commit 9fd26010f6
18225 changed files with 11622124 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
# Coordinate and Color Contract v1
## Coordinate spaces
Blender scene data is the authority. The browser adapter performs one explicit
conversion at the SceneIR -> Three.js boundary; React components never convert
coordinates independently.
| Data | Blender source | Web representation | Rule |
| --- | --- | --- | --- |
| Object transform | local/world matrices | column-major `Float32Array(16)` | preserve parent inverse and negative scale |
| Position/vector | Blender Z-up | Three.js Y-up adapter space | convert once in `three-adapter` |
| Normal/tangent | evaluated mesh | normalized buffer attributes | inverse-transpose for object scale |
| UV | mesh loop corner | `uv` buffer attribute | preserve V direction from source contract |
| Distance | Blender unit | meters only at import/export boundary | do not silently rescale scene values |
| Camera | Blender camera | Three.js camera | preserve perspective/orthographic parameters |
## Color spaces
- Base color and emission textures are decoded as sRGB unless Blender metadata
explicitly says otherwise.
- Metallic, roughness, normal, mask and weight textures remain linear data.
- Vertex colors are converted according to their Blender color attribute domain and
storage type; no implicit gamma conversion is allowed in the SceneIR serializer.
- Exposure and tone mapping belong to the Three.js renderer settings, not to
material data.
## Test fixtures
The contract is validated with an axis object, a non-uniformly scaled cube, a
negative-scale mirror, a perspective camera, an orthographic camera, an animated
object and an sRGB/linear texture pair. Every fixture records source values and
adapter values in `tests/golden/coordinate-color/`.

View File

@@ -0,0 +1,27 @@
# Web Dependency Matrix
This is the initial dependency decision for the browser build. A dependency may
move from `待验证` only after a task adds a build or browser regression test.
| Dependency or module | Decision | Web role | Evidence or next task |
| --- | --- | --- | --- |
| `blenlib`, `guardedalloc` | 保留 | Blender base/runtime utilities | W-022 |
| `makesdna`, `makesrna` | 保留 | DNA/RNA data and property schema | W-022 |
| `blenloader`, `blenkernel` | 保留 | `.blend` read/write and data blocks | W-022, W-030 |
| `bmesh` | 保留 | mesh editing and Decimate primitives | W-022, W-074 |
| `depsgraph` | 保留 | hierarchy, modifiers, evaluated mesh | W-067, W-093 |
| selected `modifiers` | 保留白名单 | Blender 5.2 types are identity-complete; evaluated parity remains fixture-gated | [modifier support matrix](modifier-support-matrix.md), W-066, W-074 |
| `windowmanager`, `editors`, `ghost` | React replacement | Blender-style UI semantics, not desktop window backend | W-018, W-019 |
| Blender `draw/gpu` viewport | 关闭首期 | Three.js is the browser renderer | W-013, W-050 |
| Python runtime and automatic `.blend` scripts | 关闭首期 | security and package-size boundary | W-117 |
| Cycles, CUDA/OptiX, Embree | 关闭首期 | server-side or native rendering only | roadmap non-goal |
| OpenVDB, USD, FFmpeg | 关闭首期 | server-side or later format modules | W-021 |
| React + TypeScript | 保留 | application UI and state | W-010 |
| Three.js (vendored) | 保留 | WebGL2 viewport and scene adapter; runtime has no CDN dependency | W-013, W-050 |
| Emscripten runtime | 保留 | Blender C/C++ to WebAssembly | W-020~W-025 |
| zlib 1.3.1 (vendored) | 保留 | gzip `.blend` decompression in Blender file reader | W-030 |
| zstd 1.5.7 (vendored) | 保留 | zstd `.blend` decompression in Blender file reader | W-030 |
| IndexedDB | 保留 | project metadata and small persistent records in StorageWorker | W-014, W-041 |
| OPFS | 保留 | large `.blend`, assets, snapshots and LOD cache | W-040, W-077 |
No CAD kernel or Bitbybit/OCCT module is part of this matrix.

View File

@@ -0,0 +1,71 @@
# Blender Depsgraph Evaluation Contract
`evaluateDepsgraph` is an explicit WebEngine Worker command intended to evaluate
the currently opened `.blend` with Blender 5.2's native loader and dependency
graph. It does not reinterpret the SceneIR modifier metadata in TypeScript.
Current status: the native module executes Blender 5.2 full loading, view-layer
synchronization, graph build, tagged update and frame evaluation in the headless
WASM runtime for the declared fixtures. The wasm32 DNA bridge recursively aligns
64-bit members, and the Web ID registry includes embedded NodeTree, Camera,
Light, Lattice and Grease Pencil data. The command returns the native
`BlenderDepsgraph/EVALUATED` report;
loader, graph or schema failures remain structured errors and never become
Three.js approximations.
The native evaluation sequence is:
1. Initialize Blender's headless data runtime once per WASM module.
2. Load the saved buffer with `BLO_read_from_memory`.
3. Synchronize view layers, build the viewport Depsgraph and apply tagged and
frame evaluation.
4. Return modifier identity/status for every evaluated object and final mesh
vertex positions and triangle indices for every mesh
object, keyed by stable SceneIR object/Mesh IDs. Each mesh also returns its
original modifier stack in order. Entries carry Blender's persistent UID,
registered type name, viewport/render/edit/cage flags, target object IDs,
the previous-stack and cross-object dependency edges, and an explicit
status: `EVALUATED`, `DISABLED` or `BLOCKED`. Blocked entries carry a stable
`errorCode`, human-readable `error` and actionable `suggestion`; they are
never silently treated as successful evaluation.
The result is validated by `parseDepsgraphEvaluation`. Every mesh must have a
16-value world matrix, exactly `vertexCount * 3` position values and exactly
`triangleCount * 3` in-range integer indices. A load, initialization or graph
failure returns the existing structured WebEngine error; it must never fall
back to a Three.js approximation.
The rigged fixture is checked against a golden written by desktop Blender 5.2.
The golden disables the fixture's Preview Decimate modifier solely to isolate
shape-key plus armature deformation. The current Web deformation evaluator
already compares final positions under the declared maximum and RMS error
budget. Native WASM Depsgraph evaluation must pass the same comparison and
repeated memory-safety runs before this contract is considered complete.
The offline regression `npm --prefix web run test:depsgraph` checks this report
schema for all declared fixtures and verifies the rigged stack order
`Armature -> Decimate`, its stack edge, the Armature target object edge and
Blender's structured "requires more than 3 input faces" Decimate block.
Drivers and constraints remain separate matrix entries. Geometry Nodes now has
two explicitly bounded native closures described below; it is not a claim of
general node-graph evaluation.
The category fixture suite adds Generate, Deform, Physics, Geometry Nodes and
Grease Pencil desktop goldens. Twenty-four category types execute native Web
implementations and compare topology/positions, including serialized
Mesh/Surface Deform bind caches and frame-6 Build/Wave output. Subdivision uses
the locally linked OpenSubdiv 3.7.0 CPU evaluator; exact Boolean uses local GMP
6.3.0; Curve evaluates through Blender's native modifier after registering the
Curves ID type. Their category goldens now pass in wasm32.
Geometry Nodes is intentionally narrower than Blender's full lazy-function
runtime. The evaluator accepts a three-node graph containing either Transform
Geometry in Components mode with literal defaults, or Set Position with an
unlinked constant selection/offset. Both use Blender mesh APIs and match desktop
goldens. Other graph shapes produce `BLENDER_MODIFIER_ERROR`; simulation/bake
state produces `GEOMETRY_NODES_SIMULATION_UNAVAILABLE` and preserves input geometry.
Other unsupported implementations retain their original DNA type code through
a disabled placeholder and report `UNSUPPORTED_MODIFIER_TYPE`; they are not
rewritten to `None`. Unsupported resource closures are validated before their
implementation can mutate geometry or enter an unavailable runtime path.

View File

@@ -0,0 +1,31 @@
# 本地依赖策略
浏览器运行时禁止从 CDN、远程 ESM 或第三方脚本地址加载功能模块。依赖分为
三类:
| 类别 | 当前模块 | 本地实现 |
| --- | --- | --- |
| 项目 vendored 运行时 | Three.js 0.185.1、OrbitControls、WebEngine glue/WASM | `web/app/src/vendor/``web/app/public/vendor/` |
| WASM 构建压缩库 | zlib 1.3.1、zstd 1.5.7 | `blender-5.2.0/extern/zlib/``blender-5.2.0/extern/zstd/`,由 Web CMake 的本地静态 target 使用 |
| npm 构建依赖 | React、ReactDOM、Vite、TypeScript | `web/package-lock.json` 锁定Vite 打入本地 `dist/assets/index-*.js` |
| 测试/工具依赖 | Playwright、ESLint、Emscripten | `web/node_modules`、系统 Emscripten 和本机 Chrome不进入浏览器产物 |
`tools/web/check-local-deps.sh` 是发布前门禁:检查 runtime dependencies 在本地
安装、Three.js 没有回退到 npm runtime import、vendor 资源存在,并扫描源码和
`dist/` 中的 CDN/远程 ESM 地址,同时按 `engine-manifest.json` 校验本地 WASM
SHA-256。npm registry 只发生在开发机首次安装阶段;发布/浏览器运行只提供
`web/dist` 的同源静态文件。离线开发需要预先保留 `node_modules` 或 npm
缓存,随后可用 `npm ci --offline` 重建,运行时不再访问 registry。
Blender Web CMake 不使用 `ExternalProject`、FetchContent 或构建时下载。zlib
和 zstd 的源码、许可证和 CMake 输入已放入 `blender-5.2.0/extern/`;浏览器只
加载 `web_engine.js` 与同源 `web_engine.wasm`,不加载 SQLite WASM、OCCT 或
任何远程模块。
可复现的离线检查命令:
```text
cd web
npm ci --offline --ignore-scripts
npm run check:local-deps
```

View File

@@ -0,0 +1,66 @@
# MeshIR Buffer Layout
This document is the versioned boundary between the Blender reader and the
Three.js renderer. The compatibility C ABI returns a JSON snapshot. The
preferred ABI separates JSON metadata from a native WBG1 geometry stream, and
the Worker transfers each typed mesh buffer without reconstructing large JSON
arrays. JSON arrays remain a fallback for older engine binaries.
## Coordinate and topology contract
- Blender source coordinates are right-handed, Z-up, with forward `-Y`.
- Positions and normals use packed little-endian IEEE-754 `float32` values.
- `indices` are packed little-endian unsigned 32-bit integers and reference
`positions` vertices.
- `topology` is `triangles`; every three indices form one triangle.
- `triangleCornerIndices` maps every index entry to the original Blender mesh
corner. It is required when UV or color attributes are present because a
single position can have multiple corner values.
- `triangleMaterialIndices` has one non-negative integer per triangle and
indexes `materialSlotIds`.
## SceneIR fields
| Field | Element count | Type | Domain |
| --- | ---: | --- | --- |
| `positions` | `vertexCount * 3` | `float32` | Point |
| `normals` | `vertexCount * 3` | `float32` | Point, normalized |
| `indices` | `triangleCount * 3` | `uint32` | Triangle corners |
| `triangleCornerIndices` | `triangleCount * 3` | `uint32` | Blender Corner |
| `uvs` | `cornerCount * 2` | `float32` | Corner, optional |
| `colors` | `cornerCount * 4` | `float32` RGBA | Corner, optional |
| `triangleMaterialIndices` | `triangleCount` | `uint32` | Face expanded to triangles |
| `triangleFaceIndices` | `triangleCount` | `uint32` | Source face for edit selection |
| `edgeVertexIndices` | `edgeCount * 2` | `uint32` | Edge endpoints |
| `tangents` | `cornerCount * 4` | `float32` | Corner tangent/sign, optional |
| `splitNormals` | `cornerCount * 3` | `float32` | Corner normal, optional |
`bounds.min` and `bounds.max` are three finite JSON numbers in source object
space. `materialSlotIds` are stable SceneIR IDs and never contain embedded
material data.
## Native WBG1 stream
The stream starts with `WBG1`, a little-endian schema version and mesh count.
Each mesh contains an ID length, eleven element counts, UTF-8 ID bytes, then
the following arrays in order:
```text
positions:f32, indices:u32, normals:f32, triangleCornerIndices:u32,
uvs:f32, colors:f32, triangleMaterialIndices:u32,
triangleFaceIndices:u32, edgeVertexIndices:u32, tangents:f32,
splitNormals:f32
```
Every count is element-based and every scalar is 4 bytes, so array starts stay
4-byte aligned. The decoder rejects truncation/trailing bytes, unknown mesh
IDs, count/summary mismatches and indices outside `vertexCount`. Topology
changes must regenerate triangle-face and edge mappings; stale source arrays
are never accepted.
`geometryStatus: "binary"` means metadata references a transferred per-mesh
buffer through `geometryBufferId`. `geometryStatus: "available"` is the JSON
fallback. After the initial WBG1 generation, `MeshGeometryDelta` carries
`meshId`, field, byte offset and transferable replacement bytes for stable-size
changes; topology or attribute-layout changes replace only that mesh envelope.
Network-style progressive sub-mesh streaming is not implied by WBG1.

View File

@@ -0,0 +1,143 @@
# Blender 5.2 Modifier Web Support Matrix
This matrix separates file recognition, dependency extraction and evaluated
result parity. Loading a modifier type is not evidence that its Web result
matches Blender desktop.
## Status levels
| Level | Meaning |
| --- | --- |
| `IDENTITY` | Type code/name, UUID, stack order and mode flags are preserved. |
| `PARAMETERS` | Declared parameters are present in SceneIR. No evaluated mesh is implied. |
| `TARGET_EDGE` | Cross-object target IDs are present in the native Depsgraph report. |
| `NATIVE_FIXTURE` | Native WASM Depsgraph behavior is covered by a Blender fixture/golden. |
| `COMMAND` | A revisioned Web command can execute and has undo/redo or isolated-preview coverage. |
| `BLOCKED` | No parity claim. An enabled unsupported/invalid entry must return a structured block. |
## Current verified set
| Modifier | Identity | Parameters | Target edge | Native fixture | Command |
| --- | --- | --- | --- | --- | --- |
| Subdivision Surface | yes | levels/type | no | desktop/WASM topology and geometry parity through local OpenSubdiv 3.7.0 CPU evaluator | no |
| Mirror | yes | axis/merge flags | optional mirror object | desktop/WASM geometry parity | no |
| Boolean (Exact) | yes | operation/solver | target object | desktop/WASM surface parity through local GMP 6.3.0 | no |
| Decimate | yes | mode/ratio/iterations/delimit | no | structured small-mesh error | Collapse/Un-Subdivide/Dissolve command |
| Armature | yes | target/group/deform flags | yes | rigged shape-key golden | enable/disable + undo/redo |
| Bevel | yes | width/segments/profile | no | desktop/WASM geometry parity | no |
| Lattice | yes | target/group/strength/flags | yes | desktop/WASM geometry parity | no |
| Curve | yes | target/group/axis/flags | yes | desktop/WASM topology and geometry parity | no |
| Hook | yes | target/subtarget/group/falloff/force | yes | desktop/WASM geometry parity | no |
| Mesh Deform | yes | target/group/grid/flags | yes | bound-cache desktop/WASM geometry parity | no |
| Shrinkwrap | yes | targets/group/distance/type/mode/limit | primary/aux targets | desktop/WASM geometry parity | no |
| Surface Deform | yes | target/group/falloff/strength/flags | yes | bound-cache desktop/WASM geometry parity | no |
| Array/Solidify | yes | fixture parameters | object edges where used | desktop/WASM geometry parity | no |
| Triangulate/Weld | yes | fixture parameters | no | desktop/WASM topology and geometry parity | no |
| Build/Wave | yes | frame/time parameters | object/texture edges where used | frame-6 desktop/WASM geometry parity | no |
| Geometry Nodes | yes | node group/default socket values | node-group edge | bounded Transform Geometry and Set Position closures match desktop | no |
| Edge Split | yes | angle/sharp flags | no | desktop/WASM topology and geometry parity | no |
| Screw | yes | axis/angle/steps/merge | optional axis object | desktop/WASM topology and geometry parity | no |
| Displace | yes | direction/strength/mid-level/space | optional mapping object | constant local-space desktop/WASM parity; resource configurations block | no |
Native `targetObjectIds` currently covers Array, Mirror, Boolean, Lattice, Curve, Armature, Hook,
Mesh Deform, Shrinkwrap, Surface Deform, Screw and Displace mapping objects.
The ordered `dependsOn` list contains the prior stack entry followed by those
external object IDs. These SceneIR entries remain `METADATA_ONLY`; the Worker
still blocks topology/LOD commands until evaluated input is available.
## Complete Blender 5.2 identity coverage
The lightweight reader now covers every DNA slot from `0` through `86`; a C++
`static_assert` fails the build when `NUM_MODIFIER_TYPES` grows without a table
update. The category-golden native whitelist contains 24 evaluated types:
`SUBSURF`, `MIRROR`, `ARRAY`, exact `BOOLEAN`, `BEVEL`, `SOLIDIFY`,
`TRIANGULATE`, `WELD`, `LATTICE`, `HOOK`, `SHRINKWRAP`, `SIMPLE_DEFORM`,
`MESH_DEFORM`, `SURFACE_DEFORM`, `CURVE`, `BUILD`, `WAVE` and the bounded
`NODES` closures, plus `SMOOTH`, `CAST`, `WIREFRAME`, `EDGE_SPLIT`, `SCREW` and
bounded `DISPLACE`.
Armature, Shape Key and Decimate have earlier dedicated
fixtures. The remaining identity-only types are:
`NONE`, `SOFT_BODY`, `UV_PROJECT`,
`PARTICLE_SYSTEM`, `PARTICLE_INSTANCE`, `EXPLODE`, `CLOTH`,
`COLLISION`, `FLUID_SIM`, `MASK`, `MULTIRES`, `SURFACE`, reserved slot `31`,
`WARP`, `WEIGHT_VG_EDIT`, `WEIGHT_VG_MIX`, `WEIGHT_VG_PROXIMITY`,
`OCEAN`, `DYNAMIC_PAINT`, `REMESH`, `SKIN`, `LAPLACIAN_SMOOTH`, `UV_WARP`,
`MESH_CACHE`, `LAPLACIAN_DEFORM`, `DATA_TRANSFER`,
`NORMAL_EDIT`, `CORRECTIVE_SMOOTH`, `MESH_SEQUENCE_CACHE`, `WEIGHTED_NORMAL`,
`FLUID`, `MESH_TO_VOLUME`, `VOLUME_DISPLACE`, `VOLUME_TO_MESH`,
`GREASE_PENCIL_OPACITY`, `GREASE_PENCIL_SUBDIV`, `GREASE_PENCIL_COLOR`,
`GREASE_PENCIL_TINT`, `GREASE_PENCIL_SMOOTH`, `GREASE_PENCIL_OFFSET`,
`GREASE_PENCIL_NOISE`, `GREASE_PENCIL_MIRROR`, `GREASE_PENCIL_THICKNESS`,
`GREASE_PENCIL_LATTICE`, `GREASE_PENCIL_DASH`, `GREASE_PENCIL_MULTIPLY`,
`GREASE_PENCIL_LENGTH`, `GREASE_PENCIL_WEIGHT_ANGLE`,
`GREASE_PENCIL_ARRAY`, `GREASE_PENCIL_WEIGHT_PROXIMITY`,
`GREASE_PENCIL_HOOK`, `GREASE_PENCIL_LINEART`, `GREASE_PENCIL_ARMATURE`,
`GREASE_PENCIL_TIME`, `GREASE_PENCIL_ENVELOPE`, `GREASE_PENCIL_OUTLINE`,
`GREASE_PENCIL_SHRINKWRAP`, `GREASE_PENCIL_BUILD`,
`GREASE_PENCIL_SIMPLIFY`, `GREASE_PENCIL_TEXTURE`.
## Blocking contract
An enabled unregistered native modifier returns `UNSUPPORTED_MODIFIER_TYPE`.
An enabled target-based modifier without a target returns
`MODIFIER_TARGET_MISSING`. An error raised by Blender itself returns
`BLENDER_MODIFIER_ERROR`. Resource/configuration-dependent Displace returns
`MODIFIER_CONFIGURATION_UNSUPPORTED`; simulation/bake GN returns
`GEOMETRY_NODES_SIMULATION_UNAVAILABLE`. A target path that reaches the owner returns
`MODIFIER_DEPENDENCY_CYCLE`. All blockers include the modifier object/name/type,
`error`, and an actionable `suggestion`. Viewport-disabled modifiers remain
`DISABLED` and do not inherit stale evaluated errors.
## Category fixtures
| Category | Blender 5.2 golden | Current Web result |
| --- | --- | --- |
| Generate | Subdivision, Mirror, Array, Boolean, Bevel, Solidify, Triangulate, Weld | All eight execute native Blender code. Subdivision matches the 26-vertex/48-triangle OpenSubdiv golden; Exact Boolean matches the 12-vertex/20-triangle surface golden. |
| Deform | Lattice, Hook, Shrinkwrap, Simple Deform, Mesh Deform, Surface Deform | All six match desktop geometry; Mesh/Surface fixtures contain real bind caches and target deformation. |
| Curve | Curve target and evaluated output in a dedicated fixture | Native Curve evaluation matches desktop topology and positions within the declared floating-point tolerance. |
| Physics/time | Build and Wave at frame 6; disabled Cloth, Soft Body and Collision | Build and Wave match desktop geometry at frame 6; simulation entries remain `DISABLED`. |
| Geometry Nodes | Self-contained Transform Geometry, Set Position and simulation-zone graphs | Constant Transform and Set Position match desktop positions/topology. Simulation zones preserve input and return `GEOMETRY_NODES_SIMULATION_UNAVAILABLE` without consuming temporal state. |
| Grease Pencil | One drawing plus all 26 GP modifier types exposed by Blender 5.2 Python | GP data loads; all modifier codes/modes are preserved and remain `DISABLED`. |
| Extended native | Edge Split, Screw and bounded Displace | All match desktop topology/positions; RGB/resource Displace preserves input and returns `MODIFIER_CONFIGURATION_UNSUPPORTED`. |
Line Art is exposed as `LINEART` rather than with the `GREASE_PENCIL_` prefix;
the generator includes it explicitly. The fixtures, desktop goldens and
comparison runner are generated by
`tools/web/generate-modifier-fixtures.py`,
`tools/web/generate-modifier-goldens.py` and checked offline with
`npm --prefix web run test:modifier-goldens`.
## Local native dependencies
Subdivision uses the local OpenSubdiv 3.7.0 source and archive under
`blender-5.2.0/extern/opensubdiv-source`. The Web build enables its CPU-only
static evaluator and disables GPU, examples, documentation and tests. The
archive MD5 is `470d53c4d4335a601c33a052ce7c33b4`; SHA-256 is
`f843eb49daf20264007d807cbc64516a1fed9cdb1149aaf84ff47691d97491f9`.
Exact Boolean uses the local GMP 6.3.0 DFSG source plus Emscripten static
archives under `blender-5.2.0/extern/gmp-source` and
`blender-5.2.0/extern/gmp-wasm`. The source archive MD5 is
`d4a3890b5e28df535b653b07798b11b2`; SHA-256 is
`bd2966e6d277f79328e894a5a9f3ba3fbf2ed2be81def5f48623e30c23fb1572`.
`WITH_MANIFOLD` remains off: Blender 5.2's verified Exact solver path uses GMP,
so Manifold is not part of the tested runtime closure. wasm32 and desktop may
choose different valid diagonals on coplanar faces; the golden therefore
compares oriented surface area and geometry instead of requiring identical
triangle indices.
`npm --prefix web run check:local-deps` verifies both source archive hashes,
the OpenSubdiv CMake source and the local GMP/GMPXX headers and WASM archives.
## Future whitelist expansion
1. Add deterministic physics cache stepping for Cloth/Soft Body/Collision;
Build and Wave are complete for the current frame golden.
2. Expand Geometry Nodes from the verified Transform Geometry and Set Position closures in small
node/dependency batches. Simulation zones, bake data, fields, instances and
the full lazy-function graph remain outside the current whitelist.
3. Enable Grease Pencil modifiers in small dependency batches; keep target and
simulation types disabled until their external resources are validated.
4. Add native geometry goldens for the remaining Generate/Deform families,
including Cast, Remesh, Multires and volume conversions.

View File

@@ -0,0 +1,78 @@
{
"schemaVersion": 1,
"packages": [
{
"name": "Blender",
"version": "5.2.0",
"license": "GPL-2.0-or-later",
"source": "blender-5.2.0/",
"notice": "Blender source and license files remain in the upstream source tree."
},
{
"name": "React",
"version": "19.2.8",
"license": "MIT",
"source": "web/node_modules/react (installed from locked npm package)"
},
{
"name": "ReactDOM",
"version": "19.2.8",
"license": "MIT",
"source": "web/node_modules/react-dom (installed from locked npm package)"
},
{
"name": "Three.js",
"version": "0.185.1",
"license": "MIT",
"source": "web/app/src/vendor/three/"
},
{
"name": "Emscripten runtime",
"version": "3.1.69",
"license": "MIT",
"source": "local emsdk"
},
{
"name": "Vite",
"version": "8.2.0",
"license": "MIT",
"source": "web/node_modules/vite (build-time only)"
},
{
"name": "TypeScript",
"version": "5.9.3",
"license": "Apache-2.0",
"source": "web/node_modules/typescript (build-time only)"
},
{
"name": "Playwright",
"version": "1.62.1",
"license": "Apache-2.0",
"source": "web/node_modules/@playwright/test (test-time only)"
},
{
"name": "OpenSubdiv",
"version": "3.7.0",
"license": "Apache-2.0",
"source": "blender-5.2.0/extern/opensubdiv-source"
},
{
"name": "GMP",
"version": "6.3.0",
"license": "LGPL-3.0-or-later",
"source": "blender-5.2.0/extern/gmp-source"
},
{
"name": "zlib",
"version": "1.3.1",
"license": "Zlib",
"source": "blender-5.2.0/extern/zlib/ (vendored build dependency)"
},
{
"name": "zstd",
"version": "1.5.7",
"license": "BSD-3-Clause",
"source": "blender-5.2.0/extern/zstd/ (vendored build dependency)"
}
]
}

19
docs/web/three-vendor.md Normal file
View File

@@ -0,0 +1,19 @@
# Three.js 本地资源
当前使用 Three.js `0.185.1`。运行时模块已从锁定的 npm 包复制到项目源码:
- `web/app/src/vendor/three/three.module.js`
- `web/app/src/vendor/three/three.core.js`
- `web/app/src/vendor/three/addons/controls/OrbitControls.js`
视口适配器只引用上述相对路径OrbitControls 的裸 `three` 导入也已改为
本地相对导入。构建产物把代码打进本地 `index` chunk不从 CDN 或网页运行时
网络加载 Three.js。`@types/three` 仅作为开发期类型依赖。
## 校验
```text
three.module.js bbf5ed13fe4373f5bd38b14ea8e62e9f157327da5638edc6d3863e08b167c9c7
three.core.js 3718df126d69c125362a03340913204470d8c50238605150e57f808840fb7759
OrbitControls.js 1e08bf297c9062aa5055a9d649d8a8458c3871aa31c7d600f535a06f567e7cad
```