Art Pipeline¶
Purpose. How a custom 3D asset goes from a Blender source file to something an .item (or
future Vehicle/DoorComponent/etc.) Model field can reference in-engine. Written because
ADR-0016 and
ADR-0017 between them resolve most
of this project's placeholder-model debt with free assets, but confirm a real, permanent gap
those sources cannot cover: all 14 Weapons/PoliceWeapons/IllegalWeapons items (the
sbox.game/facepunch/sboxassets collection has no firearms or real melee weapons at all — see
ADR-0016's second-pass finding) and, eventually, Vehicles (deferred at the feature level per
ADR-0009, not just its art). This doc exists
for that gap, not to replace free-asset sourcing as the default — free-and-suitable still wins
whenever it exists, per ADR-0016's own "Alternatives considered."
Responsibilities.
- Where source .blend files and their exports live, and why not in this repo.
- Naming, scale, and collision conventions for a custom model.
- The one step this machine can actually do (Blender export, headless or interactive).
- The one step this machine cannot do (.vmdl compilation), and where that happens instead.
Not responsible for. Rigging/animation conventions for a fully animated first-person weapon — out of scope until Documentation/Standards/06_ART_PIPELINE.md#5-proof-of-concept's static-mesh proof of concept is done and a second, harder case is actually being built. Which items get custom art vs. a free-asset match — that's ADR-0016/ADR-0017's call, this doc only covers the mechanics once an item is confirmed to need one.
Dependencies. Blender (5.2.0 LTS, confirmed installed on this dev machine), the S&box
Model Doc Editor (only available on the separate Windows machine that runs the real editor —
see the project root CLAUDE.md).
Public API. N/A — this is a process document, not code.
1. Where source files live¶
Raw .blend files and their FBX exports are large, frequently-changing binaries.
04_GIT_WORKFLOW.md §6 already excludes
"large binaries generally" from this repo's history without a separate discussion, and
Architecture/01_PROJECT_LAYOUT.md §3 already states
"no model, material or sound assets are checked in" — this doc doesn't change either rule, it
follows them for the first time there's an actual asset to place.
Convention: source .blend files and exported .fbx live in a sibling directory outside
this repo, ~/Projects/AppleJackRP-Art/<category>/<item_id>/ (e.g.
~/Projects/AppleJackRP-Art/weapons/weapon_crowbar/weapon_crowbar.blend), the same
outside-version-control treatment legacy/content/ already gets. This is a convention, not a
tool — nothing enforces it automatically. If the source-art volume grows enough to need its
own history/backup story, that is a follow-up decision (a dedicated Git LFS-backed repo is the
obvious next step), not decided here.
The compiled .vmdl/.vmdl_c output is the actual project asset once it exists, and does
belong in the S&box project's own Assets/ tree (or wherever the real editor places compiled
models) the same as any other in-engine asset — this exclusion is about the heavy, iterative
source files, not the shipped result.
2. Naming and folder convention¶
Mirror the .item id: <item_id>.blend inside <item_id>/, one folder per item. A weapon
that needs a separate first-person view model gets <item_id>_world.blend and
<item_id>_view.blend rather than two objects in one file — keeps each export single-purpose
and matches how the world/view model split already exists conceptually in the legacy
w_*.mdl/v_*.mdl naming this project's own dead placeholders still carry.
3. Scale and orientation¶
Source 2 keeps Source 1's convention: 1 Hammer unit = 1 inch. Model the asset at real-world
scale in Blender with the Unit System set to Imperial/Inches (or model in metres and scale by
0.0254 on export — either is fine as long as it's consistent), forward axis +X, up axis +Z,
matching S&box's coordinate convention (confirmed by Rotation.FromYaw/Vector3 usage
throughout this codebase's own Code/Movement/ — yaw rotates around Z).
4. Collision¶
A simple convex hull per static prop (weapon world models, packaging, etc.) is sufficient at
this scale — no per-triangle collision, no LODs; these are small hand-held/world-decoration
props, not large terrain meshes. Author the hull as a separate low-poly object in the same
.blend file, named <item_id>_collision, so the export step (below) can split it into its
own mesh on export rather than needing a second file.
5. Export (this machine can do this step)¶
Blender runs headlessly here (blender --background, confirmed:
blender -b -P script.py executes a Python script with no GUI). A minimal batch-export script:
# export_fbx.py -- run via: blender -b <item>.blend -P export_fbx.py -- <output.fbx>
import bpy, sys
argv = sys.argv[sys.argv.index("--") + 1:]
output_path = argv[0]
bpy.ops.export_scene.fbx(
filepath=output_path,
use_selection=False,
apply_unit_scale=True,
axis_forward='X',
axis_up='Z',
)
This produces an editor-ready .fbx next to the .blend source, in the same
~/Projects/AppleJackRP-Art/<category>/<item_id>/ folder from §1.
6. Compile to .vmdl (this machine cannot do this step)¶
.vmdl compilation goes through the S&box Model Doc Editor — a GUI tool, not a headless CLI
step, and part of the S&box Editor this project's root CLAUDE.md already documents as only
running on the separate Windows machine (D:/Program Files (x86)/Steam/steamapps/common/sbox/).
Once the FBX exists:
- Open the project in the real editor (directly on the Windows machine, or via
tools/AppleJackTools/connect-remote-editor.sh's remote tunnel). - Model Doc Editor → import the
.fbx→ assign the<item_id>_collisionmesh as the physics/collision hull → compile. - Note the resulting
.vmdlpath (it may not exactly match themodels/<item_id>.vmdlguess used everywhere else in this project's placeholder JSON — if it differs, that is the same kind of mechanical find-and-replace correction ADR-0016/ADR-0017 already flag for their own guessed paths, not a design problem). - Set that path as the
.itemfile'sModelfield (no__referencesentry needed — that field is specifically forsbox.gamecloud packages per ADR-0016, not project-local assets).
This step cannot be verified from this machine. Record exactly what happened (compiled clean /
warnings / errors, final .vmdl path) in handoverdaily.md once it's actually run, the same
"report which result happens" posture Assets/Prefabs/README.md already asks for.
7. Proof of concept: weapon_crowbar¶
Misc/weapon_crowbar.item is the deliberately-chosen first case: a real Equippable melee
weapon, single static mesh, no animation or view-model rig required — the simplest possible
exercise of §§1-6 end to end before attempting an animated firearm.
Done (this machine, 2026-07-31): ~/Projects/AppleJackRP-Art/weapons/weapon_crowbar/
holds weapon_crowbar.blend (a procedurally-built placeholder mesh — a bent shaft, tapered
claw tip, and ribbed handle joined into one weapon_crowbar object, plus a coarse box
weapon_crowbar_collision hull, per §4) and its export_fbx.py/weapon_crowbar.fbx output.
The FBX was re-imported and verified clean: two objects survive the round-trip
(weapon_crowbar, 48 verts; weapon_crowbar_collision, 8 verts) at real-world scale
(~0.85 m — a plausible crowbar length). Misc/weapon_crowbar.item's Model field now reads
models/weapon_crowbar.vmdl, the same kind of informed guess this project already makes for
every cloud-sourced path, following the same models/<item_id>.vmdl convention.
Not done — cannot be done from this machine: §6's actual compile step. Nobody has opened
this .fbx in the S&box Model Doc Editor yet, so models/weapon_crowbar.vmdl does not exist
as a real in-engine asset and the item still won't render. This proof of concept validates §§1-5
(the mechanical, scriptable half of the pipeline) end to end; §6 is the first real item to
exercise once a session has access to the actual editor. Record the outcome in
handoverdaily.md when that happens, per §6's own instruction.
The mesh itself is a rough placeholder, not final art — good enough to prove the pipeline
moves a .blend to an engine-ready path, not good enough to ship. Revisit the geometry once
the compile step is confirmed working, rather than polishing art that might still need a
mechanical path correction first.