# Babylon-thin-instance-outline — outline a single thin-instance (the case HighlightLayer / EdgesRenderer can't)

**URL:** <https://forum.babylonjs.com/t/babylon-thin-instance-outline-outline-a-single-thin-instance-the-case-highlightlayer-edgesrenderer-cant/63794>\
**Category:** Demos and projects\
**Tags:** shaders, highlight, thininstances, rendering, outline\
**Created:** [July 14, 2026, 8:48pm UTC](https://forum.babylonjs.com/t/babylon-thin-instance-outline-outline-a-single-thin-instance-the-case-highlightlayer-edgesrenderer-cant/63794 "2026-07-14T20:48:46Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![increasinglyHuman](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/increasinglyhuman/32/51340_2.png) [@increasinglyHuman](https://forum.babylonjs.com/u/increasinglyHuman)\
**Post date:** [July 14, 2026, 8:48pm UTC](https://forum.babylonjs.com/t/babylon-thin-instance-outline-outline-a-single-thin-instance-the-case-highlightlayer-edgesrenderer-cant/63794/1 "2026-07-14T20:48:46Z")

</div>

```auto

```

 ![Screenshot 2026-07-14 124509](https://us1.discourse-cdn.com/flex024/uploads/babylonjs/original/3X/4/a/4ab006608c462607afc7f7846476526fa490a7bc.jpeg)

The demo for the lib

 ![Screenshot 2026-07-14 134132](https://us1.discourse-cdn.com/flex024/uploads/babylonjs/original/3X/a/7/a7fdfba7ffdfb123efd06caab09fffeb9f1393f7.jpeg)  
Running inside my alpha game project.

```auto
I ran into a snag on my project and so i did a thing to resolve it. thought it worth sharing.

Thin instances are perfect for high-volume repeated geometry — but there's a
known gap: you can't outline **one** thin-instance among many. `HighlightLayer`,
`OutlineRenderer`, and `EdgesRenderer` are all-or-nothing on a thin-instance host
(outline one, outline them all), and `InstancedMesh` can't use those layers at all.

I hit this doing per-member selection on OAR-imported linksets, so I packaged the
workaround into a small, focused, zero-Babylon-patch library:

**`@poqpoq/babylon-thin-instance-outline`**

**How it works:** a parallel inverted-hull outline mesh that is *itself* a
thin-instance host — its matrix buffer mirrors the source's at the same indices.
To highlight instance `i`, copy the source matrix into the outline buffer at `i`;
to clear it, write a scale-zero matrix. Per-instance show/hide via matrix scale is
the natural Babylon idiom, so it composes cleanly.

**What's in it (v1.3):**
- Per-thin-instance outline + **per-instance color**
- **Smooth-normals preprocess** so hard-edge meshes (cubes) get continuous outlines
- **Animated silhouette effects** — pulse, colorCycle, edgeFlow, sizzle, rimFlow —
  with live param tuning (no recompile)
- Works on plain single-mesh outlines too (zero thin-instances)

**Links**
- Demo reel: 

https://www.youtube.com/watch?v=7lqRXxegcow

- live interactive demo

https://poqpoq.com/babylon-outline/

- npm: `

npm install @poqpoq/babylon-thin-instance-outline

- GitHub (MIT, ADRs, 62 tests): 

https://github.com/increasinglyHuman/babylon-thin-instance-outline

- to see it live in my alpha build - fair warning, it's definitely alpha - expect a wild ride if you to in to explore. It's implemented on geometry selection - or OAR import selection - you'd have to create your own sim and make some stuff - then select in build mode.

https://poqpoq.com/

**On prior art:** this is deliberately *not* a screen-space selection outliner — for a
unified group/selection outline, the native `SelectionOutlineLayer` and @noname0310's
excellent [Selection Outliner](https://forum.babylonjs.com/t/selection-outliner-blender-style-outlines/61598)
are the right tools. This fills the complementary gap: per-thin-instance,
silhouette-following, one outline per instance.

Feedback, edge cases, and PRs very welcome — curious whether others have run into the
same thin-instance limitation.

```

---

<div class="post-metadata">

**Author:** ![AlitarSemiramis](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/alitarsemiramis/32/49920_2.png) [@AlitarSemiramis](https://forum.babylonjs.com/u/AlitarSemiramis)\
**Post date:** [July 15, 2026, 5:46am UTC](https://forum.babylonjs.com/t/babylon-thin-instance-outline-outline-a-single-thin-instance-the-case-highlightlayer-edgesrenderer-cant/63794/2 "2026-07-15T05:46:13Z")

</div>

Super cool!

---

<div class="post-metadata">

**Author:** ![increasinglyHuman](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/increasinglyhuman/32/51340_2.png) [@increasinglyHuman](https://forum.babylonjs.com/u/increasinglyHuman)\
**Post date:** [July 17, 2026, 2:17pm UTC](https://forum.babylonjs.com/t/babylon-thin-instance-outline-outline-a-single-thin-instance-the-case-highlightlayer-edgesrenderer-cant/63794/3 "2026-07-17T14:17:10Z")

</div>

**v1.4.0 — now actually works on WebGPU 🙂**

Two fixes, and the second one is worth sharing regardless of whether you use this library.

**1. `refresh()` served stale matrices.** `thinInstanceGetWorldMatrices()` is memoised, and the cache has exactly one invalidation site (`thinInstanceSetBuffer`). `thinInstanceBufferUpdated('matrix')` doesn’t touch it — so if you move instances by writing into your own `Float32Array`, the getter keeps handing back pre-move data. Outlines silently froze in place. Also note `thinInstanceSetMatrixAt` syncs that cache **by reference** , so reusing one scratch `Matrix` across a loop makes every cached slot alias the last value written.

**2. The library never worked on WebGPU. Since v1.0.** Cause, and the generalizable bit:

```auto
// ❌ world0..3 duplicated — ShaderMaterial already adds them
new ShaderMaterial('outline', scene, path, {
  attributes: ['position', 'normal', 'world0', 'world1', 'world2', 'world3', 'myInstanceAttr'],
})

// ✅ let Babylon do it
new ShaderMaterial('outline', scene, path, {
  attributes: ['position', 'normal', 'myInstanceAttr'],
})

```

`ShaderMaterial` appends your `attributes` verbatim, then calls `PushAttributesForInstances()` when the mesh uses instances — so listing `world0..3` yourself registers them twice, both resolving to shader location 2. **WebGL binds attributes by name and tolerates it. WebGPU validates the vertex state and rejects the pipeline** — `Attribute shader location (2) is used more than once` — which took down the _entire scene_, not just the outline.

If you have a custom `ShaderMaterial` on a thin-instance host and haven’t tried WebGPU: worth a look.

My demo had hardcoded `new Engine(...)` since day one, so no run had ever exercised WebGPU. It now takes `?webgpu`, and that’s what surfaced it — within minutes.

🎮 [babylon-thin-instance-outline — demo](https://poqpoq.com/babylon-outline/?webgpu)  
📦 `npm i @poqpoq/babylon-thin-instance-outline` (≤1.3.1 deprecated — WebGPU-fatal)

Both of these trace back to a generous and very thorough review from @labris, who went through the library line by line and got me looking in the right place. Thank you.
