- new snippet geo_map_render.js: [map] inline geomaps (tree order, tint, theme-following), [gpx] stats card + elevation profile with hover cursor (km from start, d-height, vertical guide), [yt] privacy click-to-load facade, [video]/[audio] inline players fed from the new geoData indexes - 3d_model_viewer.js: [cad] keyword + title/ID resolution via geoData.cad, sizes/captions, real occt-wasm ESM pair (fixes 'STEP worker error'), code-span-safe keyword scan (docs can show examples) - blog_generator.js: buildGeoData() v6 – maps (geolocation + geoShape point/line/polygon + child GPX tracks), gpx/cad/media indexes, branch-change rebuild for route reordering - generated/geo_data.js placeholder; docs/embed-keywords.md (new) + embed-3d-model Option D; README layout/wiring/notes tables updated - license: runtime components (MapLibre ISC, VersaTiles MIT/ODbL, YouTube) - hygiene: removed leaked note IDs and instance domain from theme docs
90 lines
5.1 KiB
Markdown
90 lines
5.1 KiB
Markdown
# Embedding a 3D model (STEP / STL) in a note
|
||
|
||
The share can render `.step` / `.stp` / `.stl` models interactively (three.js + occt-import-js,
|
||
hosted locally). The viewer fills the available screen width (full-bleed, ~`100vw`) with a
|
||
height based on the viewport (`min(70vh, 900px)`), so standalone model pages use the maximum
|
||
available space instead of the readable content width. **Inline viewers embedded in text
|
||
articles** (Options B and C) are limited to the content width (`model-viewer-inline`). The caption below the model always shows
|
||
`<file name> · <size> · <triangle count>` (e.g. `Wrench.stl · 711 KB · 14.6k triangles`).
|
||
|
||
There are four ways to embed a model, depending on how you store the file.
|
||
|
||
## Option A – Model as its own note (file note)
|
||
|
||
1. Create (or upload) a **file note** and make sure its **title ends in `.step`, `.stp` or `.stl`**,
|
||
e.g. `bracket.step` or `rear_housing.stp`.
|
||
2. Put it under a category in the blog and set `publish=true`.
|
||
3. The note's share page then shows the interactive **3D viewer** automatically:
|
||
drag to rotate, scroll to zoom.
|
||
|
||
## Option B – Model embedded inline in a text note (attachment)
|
||
|
||
1. Upload the STEP/STL file as an **attachment** of the note:
|
||
drag & drop it onto the note, or use the attachment dialog (paperclip icon).
|
||
2. **Rename the attachment** so its title ends in `.step`, `.stp` or `.stl`
|
||
(the viewer detects a model by the file name). Example: `flange.step`.
|
||
3. **Insert the attachment link** into the note body:
|
||
right-click the attachment → "Insert link", or drag the attachment into the text.
|
||
4. On the share, that link is automatically replaced by the embedded 3D viewer.
|
||
|
||
## Option C – Model embedded inline from a file note (recommended for blog posts)
|
||
|
||
This lets you write blog posts that contain models inline, referencing a model that also
|
||
exists as its own (published) file note — the model stays in one place.
|
||
|
||
1. Create the model as a **file note** (title ends in `.step` / `.stp` / `.stl`),
|
||
publish it (see Option A). The viewer needs it in `blog_data`, i.e. it must be a
|
||
published article reachable in the blog tree.
|
||
2. In your **text note**, add a link to that file note, e.g.
|
||
`[Wrench.stl](#root/<noteId>)` (markdown) or drag the note reference into the editor.
|
||
3. On the share, the link to a model file note is replaced by the inline viewer.
|
||
You can embed several models per post this way.
|
||
|
||
> Tip: STL (plain triangle meshes) is rendered with three.js only; STEP (CAD B-rep) is
|
||
> parsed by **occt-wasm** (OpenCASCADE **V8**, WASM, MIT/Apache-2.0) in a **Web Worker**
|
||
> (module worker, non-blocking). The first STEP view downloads the ~22 MB WASM once and
|
||
> then caches it in the browser.
|
||
> STEP tessellation is set to `linearDeflection: 0.4, angularDeflection: 0.2`
|
||
> (≈480k triangles for the ignis battery module; tuned for mobile).
|
||
|
||
## Option D – `[cad]` keyword (editor-safe, no HTML or links)
|
||
|
||
Plain-text keyword, robust against editor re-saves (unlike raw HTML embeds, which CKEditor strips):
|
||
|
||
```
|
||
[cad <id|title>] # e.g. [cad base] or [cad __MODEL_FILE_NOTE_ID__]
|
||
[cad <id|title>|small] # small | medium | large (viewer height)
|
||
[cad <id|title>|Own caption] # free text as caption
|
||
```
|
||
|
||
The key resolves through the **`cad` index** in `window.geoData` (built by `blog_generator.js`,
|
||
scans the blog tree for `.stl` / `.step` / `.stp` file notes; the extension may live in the
|
||
note title **or** `#originalFileName`). The model file note does **not** need its own `publish`
|
||
label — it only has to be inside the blog subtree. See `docs/embed-keywords.md` for the whole
|
||
keyword family (`map`, `gpx`, `cad`, `yt`, `video`, `audio`).
|
||
|
||
## Requirements
|
||
|
||
- The `3d model viewer` script must be wired: `~shareHtml → 3d model viewer`
|
||
(inheritable) on the blog root, `shareHtmlLocation=body:end`.
|
||
- The five libraries must exist as notes and be referenced by the script via the
|
||
placeholder tokens in `scripts/3d_model_viewer.js`:
|
||
`__THREE_ID__`, `__THREE_ORBIT_ID__`, `__THREE_STL_ID__`, `__OCCT_JS_ID__`
|
||
(the occt-wasm **bundle**), `__OCCT_WASM_ID__` (occt-wasm.wasm) – see the README
|
||
installation for the note titles. The STEP worker is a **module worker** (`type: "module"`),
|
||
so the browser must support ES modules in workers (all modern browsers).
|
||
- **Mobile compatibility**: the mesh is split into chunks of ≤65000 vertices
|
||
(`chunkGeometry`, `Uint16` indices) so it renders on GPUs without
|
||
`OES_element_index_uint`; the camera near/far is tightened after `fit()` for 16-bit
|
||
depth buffers.
|
||
- For **inline embedding from a file note (Option C)** the `blog_data` note must be
|
||
present and the target model must be a published article (the viewer resolves
|
||
`./<alias>` links against `window.blogData`).
|
||
|
||
## Trilium app widget (independent of the share)
|
||
|
||
The same viewer is also available **inside Trilium itself** (independent of the blog):
|
||
a `note-detail-pane` widget (`app/3d-model-viewer-app.jsx` + `app/3d-worker.js`) renders
|
||
the viewer whenever you open a file note whose title ends in `.step` / `.stp` / `.stl`.
|
||
The worker is loaded from a code note (not a Blob) so it works under the app's CSP.
|
||
Wire it by giving the JSX note the label `#widget=3dModelViewer` and reload the app. |