Blender Producer Guide
Everything Loom does on the Blender side: what streams, what does not, and the authoring properties that survive a restart. Pair it with the Unity or Unreal quick start for the engine half.
Requirements: Blender 5.0 or newer (tested on 5.0, 5.1 and 5.2), a Unity or Unreal editor on the same machine (loopback TCP).
1. Install, and where the panel lives
- Edit → Preferences → Add-ons, the ▾ menu → Install from Disk…, choose a zip of the
blender/loom/folder, and enable Loom in the list. - The panel is in the 3D Viewport → N sidebar → Loom tab. Its root panel is Loom Live Sync; everything else is a sub-panel under it.
Loom ships as a Blender extension and declares exactly one permission: network, to reach the editor’s listener at 127.0.0.1:8787. Every setting below is stored in the .blend, so a project keeps its endpoint and its toggles.
2. The panel at a glance
| Panel | What lives there |
|---|---|
| Loom Live Sync (root) | link status, Scope, the live count, Track/Untrack/Exclude/Include, Connect |
| Connection | Host, Port, Auto-connect on load, Debounce |
| Geometry | Normals, UVs, Vertex Colors, Shape Keys, Armatures, Weld Vertices |
| Scene Structure | Collections, Instances, Linked Duplicates, Multi-scene, World, Skip Boolean cutters, Skip SNAP_/SOCKET_ markers |
| Routing & Selection | Routing, Mirror Selection, Accept property edits from the editor |
| Materials | Sync Materials, Pre-flight Scan, texture, graph and bake options |
| Active Object | the per-object status line, the flags, Prefab reference, Routing → Editor |
| Tracked Objects | the list of what is actually streaming, with per-row actions |
Of the sub-panels, only Materials is open by default; the rest start collapsed.
3. Connect, and what “scope” means
Press Connect. The status box reads Offline → Waiting for the editor… → Connected; while it waits it shows the endpoint it is trying and the one thing to do about it, Start the Loom listener in the editor. Connected, it reads 12 objects · 3 queued.
Scope decides what streams, and it is deliberately narrow by default:
- Selected only (default) — selecting an object tracks it. It streams, keeps streaming while deselected, survives a reconnect or a Blender relaunch, and leaves the editor only when you Untrack it. Turn off Track on select to manage the set with the Track / Untrack buttons alone. Track the whole model (on by default) widens every one of those gestures to the clicked object’s whole parent tree: click a character’s hair and the whole character streams. Untrack takes the whole model back out; Exclude stays per-object, so it is the way to leave one piece behind.
- Whole scene — every streamable object except the excluded ones.
- Collection — the chosen collection and its children.
Exclude / Include work in every scope: an excluded object never streams and is removed from the editor the moment you exclude it. Above those buttons a live count says what will happen before you connect — 12 objects · 90 instances will sync · 3 excluded. Once connected the same line reads in scope where it read will sync. Generated instances are folded into that same sentence because they are the easy way to put hundreds of objects into an editor by accident.
When nothing would sync yet, the count is replaced by a choice rather than a zero: Nothing will sync yet. What do you want to send?, with one button for Whole scene · 43 objects, one for the active collection when it has anything in it, and a reminder that clicking a model in the viewport is the third answer. (With a Collection scope and none chosen, it reads Choose a collection to stream.)
A model only part of which streams gets its own warning, Only 3 of 4 parts of ‘Rig’ will sync, with a Track all button beside it. The usual way to get there is to parent a new mesh to a character that was already tracked.
4. What never streams
Active Object answers this per object — it names the reason and the pref that undoes it — but the rules are worth knowing up front:
- Boolean cutters. An operand that only exists to cut a Boolean modifier (displayed as Wire / Bounds, or hidden from render) is skipped; the cut result on the target streams as normal, and re-streams live as you move the cutter. Status: Boolean cutter — auto-skipped (Structure › Skip Boolean cutters).
SNAP_/SOCKET_marker empties. Kit snap points and attachment sockets are authoring scaffolding, not level content. The match is case-sensitive and empties only — a mesh namedSNAP_Bracketis real geometry someone named after its job. Anything parented to a marker still streams. Skipped markers are counted as neither synced nor excluded: excluded means “kept out on purpose”, not “absent”.- Excluded and frozen objects, and types with no faithful equivalent on the wire. The status line says Not streamed — Volume objects aren’t synced and so on. An armature reads Streams via its deformed meshes.
5. Materials, node graphs and the pre-flight scan
Materials are kept off the realtime path — press Sync Materials to push them. Supported node graphs become real generated shaders in the editor; anything else falls back to a faithful Principled material.
- Textures — encode and send image textures with the materials.
- Node Graphs — translate supported graphs; off leaves everything on the Principled path.
- Bake to Texture + Bake Resolution — the escape hatch for a graph Loom cannot represent: bake it to albedo, roughness and normal maps via Cycles instead. It is opt-in per material — with the material active, the checkbox reads Bake “MyMaterial”.
Pre-flight Scan works offline; that is the point. It reports each material as transpiled to HLSL, fell back to Principled, baked to maps or plain Principled, and names the first few fallbacks with their reason. Underneath, the same scan summarises the prefab keys in scope — 3 prefab keys in use · 92 placements, then a row per key. Keys are counted in placements: a keyed mesh datablock shared by ninety objects reads as ninety. The scan stops at what the .blend asks for; the variant pool lives in the engine registry, which is why the row under it says The variant pool is checked in the engine window instead of implying a validation that never happened.
6. Prefab keys — the Prefab reference box
Active Object › Prefab reference is where a greybox object becomes a reference to your real prefab or Blueprint. On an unkeyed object it says Streams as geometry — set a key to spawn your prefab instead and offers Set Prefab Key…. The dialog has four fields:
- Prefab key — what your engine-side registry maps to an asset (
pillar_a). - Apply to — All sharing the mesh (the default) or This placement only. This is the whole trick: the key on the mesh datablock covers every linked duplicate (Alt+D) at once — three pillar meshes, ninety placements, three keys.
- Variant — which prefab of the key’s pool to spawn (
0= the base). - Variant name — the engine asset’s own name, which overrides the index. Prefer it whenever the pool might be reordered: index
2means a different piece the moment someone inserts a row, a name does not. Blender cannot check the name, because the pool is engine-side; the editor does, and falls back to the base with a warning.
Once keyed, the box reads back what is actually stored: Key (mesh data) or Key (object), Shared by 90 linked duplicates when the datablock has that many users, and a plain reading of what will be sent — variant Pillar_Broken (name), variant 3 (index) or variant 0 (base prefab). The buttons become Change…, Clear to greybox and Scatter pool….
They are plain custom properties — loom_prefab and loom_variant — so any script or kit tool can write them and Loom notices within half a second. Clear to greybox removes both, from the object and its mesh data, and the object streams as ordinary geometry again. The per-object status line mirrors all of it: Prefab reference → pillar_a (mesh data) · variant Pillar_Broken.
7. Scatter variants
Ninety copies of one pillar all showing the same variant is not a level. With keyed objects selected, Scatter pool… deals a pool out over every in-scope placement of each selected mesh datablock. The dialog asks for two numbers:
- Pool size — base plus variants. This is the one number Blender has to ask for rather than read, because the pool lives in the engine registry.
- Seed — pre-filled from the seed already stored on the keyed selection’s datablock (42 for a group nobody has scattered yet), so re-opening the dialog shows what produced the current arrangement, and typing +1 is the re-roll.
A scatter is a write, not a roll: each placement gets a concrete loom_variant written into the .blend and the seed is stored on the datablock as loom_scatter_seed, so the arrangement is stable across reconnects and relaunches. The box then shows scattered · seed 42, and the report reads Scattered 90 placements over base + 3 variants (seed 42).
The result is reproducible from either application: placements are ordered by ascending object id, the one ordering Blender and both engines can derive independently, and the generator is the same function all three run. The seed rides both ways, so each editor’s Scatter pool… popup shows the same number this dialog does.
The button is off when the selection carries no prefab key, with the reason on the button: Assign a prefab key first — a scatter draws from the key’s variant pool.
8. Blockouts — what is left to replace
Active Object has a Blockout checkbox beside Freeze, and a bulk pair of buttons, Mark as blockout / Unmark blockout, over the whole selection. The pairing with Freeze is the point: both are per-object state that changes nothing about the geometry. Freeze stops the stream; a blockout still streams exactly as before — the flag is a label on the work, not a change to what Loom sends.
Once anything carries the flag, the scope box grows one line: 62 of 210 blockouts replaced, with a ? that opens the explainer at the page about it. Replaced means blockout and keyed — the same rule both editor windows apply, so the three surfaces agree about how much of the level is done. Assigning or clearing a key never touches the flag. The per-object status says the same thing for one object: Blockout · awaiting replacement — streams as geometry.
9. The Tracked Objects list
The counts in the scope box say how many; this panel says which, which is the question you actually ask when the number looks wrong. Its filter has four modes:
- Streaming — what the current scope is sending.
- Excluded — objects explicitly excluded, and only those.
- Blockouts — the flag, whatever the scope says; a replacement backlog does not stop existing because you narrowed the scope.
- All — every streamable object in the file. This is the only filter that can show an object linked into no scene, which is half of why the list exists.
Each row carries its own actions — select, freeze, exclude/include, and untrack under Selected only — and every one of them addresses the object by name, so untracking row 40 never disturbs the viewport selection you are working with. The list’s own search box ANDs with the filter, and rows are alphabetical.
10. Routing, and letting the editor write back
Active Object › Routing → Editor edits whichever of the four routing custom properties exist — loom_layer, loom_tag, loom_static, loom_sorting_layer — with Add to create the missing ones. Remove is not decoration: removing the properties is what clears the routing in the editor, because a blank field is still a routed field.
Routing & Selection holds the two prefs that decide how much the editor may touch:
- Mirror Selection — selecting an object here highlights its counterpart there.
- Accept property edits from the editor (on by default) — the reverse direction, and the only pref whose consequence is a change to this
.blend.
What that permission covers is a closed list — prefab key, variant, scatter seed, blockout, tracked/excluded/freeze, and the four routing properties — and nothing else. Three further rules hold whatever the editor sends: only objects Loom is currently streaming can be written, so an editor cannot reach into a part of the file you deliberately kept out of the stream; a datablock linked from another .blend is refused up front, naming the file to make local; and never geometry, under any setting. Every accepted write also pushes an undo step, so Ctrl+Z in Blender takes it back (one undo step per write). Should Blender ever refuse the step (seen only in the instant after a file load), the edit itself still applies and Loom retries on the next write.
11. “How replacement works”
The four-page explainer is the same copy Unity and Unreal show, word for word: 1 · What streams, 2 · What a key does, 3 · Variants and pools, 4 · Greybox → final. There is no first-run tour — it sits exactly where the questions come up: behind a ? on the Prefab reference header and on the blockouts count line, and as How replacement works › inside the Scatter pool… dialog. It is a popup with ‹ Back / Next › and a 2 / 4 counter. It documents, it never acts — no page can write anything.
12. Tile test — checking a kit piece’s seams
A modular piece only proves it tiles when it sits beside copies of itself. Make Tile Test… (Active Object › Game-ready, or Right-click › Loom) places copies around every selected mesh, stepped by the piece’s bounding box, or by its own socket and plug pair so a corner piece turns the chain and a curved corridor section curves it. Reach sets how many cells the grid goes each way; the default is a 3 × 3 grid.
The copies are linked duplicates of the piece and children of it: fix a vertex on the edge and every copy has the fix, move the piece and the grid comes with it. They stream like any other object, so you see the seams under the engine’s own lighting, and both bakes leave them out. Run it again after changing the piece’s modifiers; Clear Tile Test removes the grid.
13. Rigid bodies — physics in the engine
Set a rigid body up where you always have, Properties ▸ Physics ▸ Rigid Body, and it streams as a real physics body. Press Play in Unity or PIE in Unreal and it falls, slides, tumbles and pushes the way Blender’s own simulation does.
- Type, shape, mass, friction, bounciness, damping, margin, deactivation and the collision collections all travel. Active becomes a simulated body, Passive a collider that never moves, Animated a body moved by its animation that pushes what it meets, and a Compound parent one body made of its rigid-body children.
- Loom sends the shape Blender actually collides with, not the one the Shape menu names: a scaled sphere takes its size from one axis only, a convex hull grows by its margin, and every shape sits on the object’s origin. The engine never has to guess.
- The Active Object panel shows what the engine will get for the selected body, and where that differs from the Physics tab.
- A simulated body streams where you placed it, not where Blender’s simulation has it at the current frame, because the engine runs its own simulation. For Blender’s exact result, use Object ▸ Rigid Body ▸ Bake to Keyframes and the bodies stream as animation.
- Turn the feature off with Preferences ▸ Rigid bodies in the Loom panel.
Tips and toggles
-
Pause — beside Disconnect. It keeps the connection but holds every change (moves, edits, new and deleted objects) and sends what changed on Resume. Use it for a heavy edit you want to land in one go. Both editors say Blender has paused. Freeze, by contrast, pins single objects.
-
Debounce — the minimum interval between publishes (0.033 ≈ 30 fps). Raise it on a very heavy scene, lower it for the tightest feedback.
-
Auto-connect on load — start live sync when this file opens.
-
Weld Vertices — smaller uploads, but a welded object always sends a full mesh instead of a lightweight deform, so it suits static geometry.
-
Multi-scene — tags streamed objects with their Blender scene so the editor namespaces each non-active scene under its own sub-root. Off keeps one flat hierarchy.
-
World — background colour and strength become ambient, an Environment Texture becomes the skybox, mist becomes fog.
-
Freeze vs Blockout — Freeze pins an object in the editor and stops updating it; Blockout only labels what the object is. Neither changes the geometry.
-
Collider and LOD naming — name proxies
UCX_,UBX_,USP_,UCP_,UMC_and siblings<base>_LOD0..n. Both are consumer-side conventions read off the object name, so there is nothing to switch on here, and the Game-ready generators make the proxies and LOD chains for you. -
Language — the panel, both editors and the guide speak English and Korean, and the editors follow Blender’s language across the link.
Troubleshooting
- Status stuck at “Waiting for the editor…”. The editor’s listener is not up. Press Start Listener in the Loom window or Loom tab. This is a calm wait, not an error.
- An object is not in the editor. Select it and read Active Object: the status line names the reason and the pref that undoes it.
- A geometry-nodes scatter arrives empty. Check the tree really instances. Realize Instances before the Group Output is the always-correct fallback, at the cost of per-instance dedup.
- An assign from the editor comes back refused. Either Accept property edits from the editor is off (the message says so, and names the panel), or the object’s datablock is linked from another
.blend(the message names the file). Make it local and retry. - Materials look flat in the editor. Press Sync Materials; they do not ride the geometry stream.
The engine halves of all this are in the Unity and Unreal quick starts. See Architecture for how the link works.