diff --git a/gpu-skinned-herds.html b/gpu-skinned-herds.html
index 80cd38f..c0dc8fe 100644
--- a/gpu-skinned-herds.html
+++ b/gpu-skinned-herds.html
@@ -280,7 +280,7 @@
-
We built a GPU skinned-instance renderer into Tinqs Engine that packs every pose into a single texture, uploads once, and draws every instance in one call. 25 crocodiles on screen right now. 1,000+ projected. Same bone count, same animation fidelity — a tiny fraction of the cost.
+
We built a GPU skinned-instance renderer into Tinqs Engine that packs every pose into a single texture, uploads once, and draws every instance in one call. 25 crocodiles confirmed first. Then we threw 1,000 animals — 12 types mixed, random-walking — at it and the GPU didn't flinch. Same bone count, same animation fidelity, a tiny fraction of the cost.
Why the engine needs to change
The standard Godot approach — one Skeleton3D + one MeshInstance3D per character — works for a handful of animated entities. It breaks down hard at crowd scale:
@@ -325,7 +325,7 @@ data.update() # upload only dirty instances, not the whole textureThe lesson: doctests catch logic. Rendering catches truth. You need both.
What's driving it
In Ariki, the sim tracks animal migration across a 12km archipelago. AnimalHerdRenderer.cs groups sim ViewerState.animals by type, feeds positions to skinned_herd.gd (a reusable per-type herd backend), which drives the renderer. One AnimationPlayer animates a single driver skeleton; poses propagate to every instance.
-The crocodile herd scene is 25 instances, one draw call. The same pipeline projects to 200–1,000 before the GPU budget even notices.
+The crocodile herd scene was 25 instances, one draw call. The perf test scene does 1,000 animals across 12 types — Boar, Cow, Crab, Crocodile, Deer, Fish, Goat, Hen, Pig, Rabbit, Sheep, Tiger — each type its own GPU herd, all mixed, all random-walking, FPS holding steady.
What's deliberately not here
- No C# wrapper. Instantiate from GDScript via
ClassDB.instantiate() — the binding surface is small and stable.
@@ -333,7 +333,7 @@ data.update() # upload only dirty instances, not the whole textureNo GPU occlusion or LOD. That's the game's job. The engine provides the tool; the game decides what to draw.
Get the build
-Pre-built editor binaries with agent_skinned baked in — no engine compile required:
+Pre-built editor binaries with agent_skinned baked in — no engine compile required. The game's animal_perf_test.tscn lets you toggle 10 / 100 / 1000 animals and read live FPS:
| Platform | Binary | Engine commit |
|———-|——–|—————|
| macOS ARM64 | tinqs.macos.editor.arm64.mono | 4fe1323 (4.6.4, Xcode 26.3) |
diff --git a/posts/gpu-skinned-herds.md b/posts/gpu-skinned-herds.md
index a1b3a28..e86100f 100644
--- a/posts/gpu-skinned-herds.md
+++ b/posts/gpu-skinned-herds.md
@@ -12,7 +12,7 @@ author_role: "CTO & Developer, Tinqs"
---
Godot gives you one `Skeleton3D` per character. Want 200 animals in a herd? That's 200 skeleton nodes, 200 draw calls, and 200 `AnimationPlayer` ticks every frame. Want 1,000? Now you're measuring in seconds per frame, not frames per second.
-We built a GPU skinned-instance renderer into Tinqs Engine that packs every pose into a single texture, uploads once, and draws every instance in one call. 25 crocodiles on screen right now. 1,000+ projected. Same bone count, same animation fidelity — a tiny fraction of the cost.
+We built a GPU skinned-instance renderer into Tinqs Engine that packs every pose into a single texture, uploads once, and draws every instance in one call. 25 crocodiles confirmed first. Then we threw 1,000 animals — 12 types mixed, random-walking — at it and the GPU didn't flinch. Same bone count, same animation fidelity, a tiny fraction of the cost.
## Why the engine needs to change
@@ -86,7 +86,7 @@ The lesson: doctests catch logic. Rendering catches truth. You need both.
In [Ariki](https://www.arikigame.com), the sim tracks animal migration across a 12km archipelago. `AnimalHerdRenderer.cs` groups sim `ViewerState.animals` by type, feeds positions to `skinned_herd.gd` (a reusable per-type herd backend), which drives the renderer. One `AnimationPlayer` animates a single driver skeleton; poses propagate to every instance.
-The crocodile herd scene is 25 instances, one draw call. The same pipeline projects to 200–1,000 before the GPU budget even notices.
+The crocodile herd scene was 25 instances, one draw call. The perf test scene does 1,000 animals across 12 types — Boar, Cow, Crab, Crocodile, Deer, Fish, Goat, Hen, Pig, Rabbit, Sheep, Tiger — each type its own GPU herd, all mixed, all random-walking, FPS holding steady.
## What's deliberately not here
@@ -96,7 +96,7 @@ The crocodile herd scene is 25 instances, one draw call. The same pipeline proje
## Get the build
-Pre-built editor binaries with `agent_skinned` baked in — no engine compile required:
+Pre-built editor binaries with `agent_skinned` baked in — no engine compile required. The game's `animal_perf_test.tscn` lets you toggle 10 / 100 / 1000 animals and read live FPS:
| Platform | Binary | Engine commit |
|----------|--------|---------------|