Land of Lor — Engineering Note

Sourcing & Building 3D Objects

How the game should get its many low-poly, stylised creature and gear models — evaluated against the core mechanic: composing creatures from parts and attaching gear at runtime.
Written 25 July 2026 · companion to docs/RECIPES.md and the pocs/object-gallery/ proof of concept · answers Kris's open flag in RECIPES.md: "BUT THIS IS AN ASSUMPTION I MUST CHECK WITH CLAUDE." (3D models over 2D sprite sheets — confirmed correct, see below.)
Part 1 — Three sourcing approaches, tested Verdict & what got discarded Morphing vs. discrete — which technique for which game need Conclusion & how this maps onto the recipe system

1Three approaches, tested against this project

The game needs a large and growing library of objects, and per docs/RECIPES.md the core mechanic is combinatorial: a Horse plus a filled Wings slot becomes a Pegasus; a humanoid torso plus a horse body becomes a Centaur; gear (hats, weapons, shirts) attaches to named sockets on a creature. Whatever sourcing method is chosen has to serve that shape of problem, not just "get some 3D models." Three approaches were actually tried, not just reasoned about in the abstract.

A. Procedural primitive-composition in Godot

Chosen — backbone

Build every object as a small scene tree of Godot primitives — BoxMesh, CylinderMesh, SphereMesh, CapsuleMesh, TorusMesh, PrismMesh — each a MeshInstance3D with a flat StandardMaterial3D (solid albedo colour, shading_mode = Unshaded or a single hard directional light with no smoothing group). CSG nodes (CSGBox3D, CSGCombiner3D, boolean unions) are useful for one-off shape sculpting but bake to static meshes for runtime — plain MeshInstance3D composition is lighter and was used for everything actually shipped in the POC.

Tested: every creature and gear scene in pocs/object-gallery/ is built this way — e.g. the cute basic creature is two SphereMeshes (a body ball and a head ball) plus four stubby CapsuleMesh legs, all children of one Node3D root. Attachment points are plain Marker3D nodes named socket_head, socket_right_hand, socket_back, etc., placed by eye in the editor.

Fit for combine/attach mechanicExcellent — a creature is a scene tree of parts; adding a Marker3D socket is a one-line editor operation, and gear scenes reparent onto a socket with zero import friction, because everything already lives in the same engine, same units, same material system.
Iteration speedFast — no external tool round-trip; tweak a primitive's size/position in the Godot inspector and see it live.
Visual fitGood — flat-shaded primitives naturally produce the "low vertex count, clearly recognisable, not photoreal" look the brief asks for.
Scaling to "many objects over time"Good with discipline — fine by hand up to dozens of objects; past that, a small in-house primitive-kit (a library of pre-styled part scenes: "stubby leg", "round head", "pointed hat") keeps it from becoming repetitive boilerplate. This is a process risk, not a technical one.
Complex organic shapes (dragons, faces)Limited — primitives alone struggle with anything that needs a genuinely sculpted silhouette. Acceptable for a stylised game; would need a heavier pipeline (Approach C, or an actual DCC tool) for hero assets later.

B. CC0 assets via a GitHub-hosted mirror

Supplementary source

The brief predicted direct egress to kenney.nl / poly.pizza / quaternius.com would be blocked by the container's allowlist. That prediction was wrong — this container's egress allowlist is more permissive than expected, and direct requests to all three domains returned HTTP 200. So in this specific environment, the "GitHub mirror" workaround wasn't strictly necessary. It's still worth documenting, because (a) allowlists can and do change between environments/deployments, and (b) GitHub mirrors are frequently better-organised for engine use than the original download pages.

Tested: a GitHub code search for repos mirroring Kenney and Quaternius packs turned up several actively-used, already-Godot-adapted mirrors, e.g. kirbycope/godot-quaternius (a whole Godot project pre-wired with Quaternius' Fantasy Props, Modular SciFi, Universal Base Characters, etc. packs, each with its own _README.md crediting the source) and Calinou/kenney-* (individual Kenney packs repackaged "for quick use in Godot", maintained by a Godot core contributor). Repo contents were confirmed reachable and non-empty via the GitHub API without needing a full clone.

LicensingCC0 for both source libraries — Kenney and Quaternius both publish under CC0 (public domain equivalent): no attribution legally required, no share-alike, no revenue-share, safe for a commercial Christmas 2026 release. This matters a lot more than it sounds — anything CC-BY or "free for non-commercial" would need per-asset attribution tracking or would be an outright blocker for a paid/monetised release, which doesn't scale once you have hundreds of props.
Fit for combine/attach mechanicWeak-to-moderate — these packs are pre-modelled, complete objects (a finished sword, a finished barrel), not part-libraries designed for socketed recombination. Useful as whole props or as a source of individual meshes to strip for parts, not as the compositional backbone.
Visual consistencyNeeds curation — different packs have different scales, poly budgets, and colour palettes; mixing them into one game requires a pass to reconcile scale/material style, which is exactly the kind of hidden cost "just download some assets" glosses over.
Best use hereOne-off environment dressing and props that aren't part of the creature/gear recombination system — barrels, crates, rocks, foliage, furniture for the casting-table room. Not creatures, not socketed gear.

C. Python mesh pipeline (trimesh → glTF/GLB)

Discarded as backbone

trimesh installed cleanly via pip and was used to build a real test asset: a small creature (a box body, an icosphere head, four cylinder legs) composed with translations and exported to a valid, correctly-sized .glb (~9.7 KB) in a few lines of Python. It works, and it's a legitimate way to batch-generate or algorithmically vary meshes outside the engine.

body = trimesh.creation.box(extents=[1.0, 0.6, 0.5])
head = trimesh.creation.icosphere(subdivisions=1, radius=0.3)
head.apply_translation([0.65, 0, 0.15])
legs = [leg.copy().apply_translation([x, y, -0.4]) for x in (-.35,.35) for y in (-.2,.2)]
trimesh.Scene([body, head] + legs).export('creature.glb')  # imports straight into Godot
Fit for combine/attach mechanicPossible, but redundant — you'd still need Godot-side socket metadata (Marker3D nodes) on the imported result, so you gain nothing over building directly in Godot for anything that's fundamentally "boxes and spheres in a hierarchy" — which is most of this game's objects.
Where it actually winsBatch/parametric generation — e.g. programmatically generating a whole family of variant meshes (say, 64 slightly different crystal shapes keyed off hexagram data) as a build step, then importing the .glb files. That's a real future use case for the recipe/element system, just not needed for the object-gallery POC.
Iteration speedSlower — edit Python → re-run → re-export → re-import into Godot → reimport asset, versus tweak-and-see in the Godot editor directly.
bpy (Blender as a pip module)Assessed, not installedbpy gives full Blender modelling/sculpting/UV/rigging power from Python, which is real headroom for later hero assets or rigged animation, but it's a heavy dependency (hundreds of MB, its own Python ABI constraints) for what is, right now, a low-poly primitive-composition game. Worth revisiting if the game grows organic/sculpted creatures or needs skeletal animation baked outside the engine — not worth installing for this POC.

2Verdict

Kris's prior was correct. Procedural primitive-composition directly in Godot is the right backbone, precisely because it lines up with the combinatorial/attachment mechanic described in RECIPES.md: a creature is already, conceptually, a set of slot-filling parts — building it as a literal Godot scene tree of parts with named Marker3D sockets makes the engine representation identical to the game-design representation. CC0 GitHub-mirrored assets are a good supplementary source for one-off, non-recombining props (environment dressing), not for the creature/gear system itself. The Python/trimesh pipeline is a legitimate future tool for parametric batch-generation (e.g. generating element-keyed crystal variants at build time) but adds an unnecessary round-trip for the hand-authored, in-editor part composition this POC needed.

What got discarded and why, briefly:

3Morphing vs. discrete — which technique for which game need

This question matters because it drives how every future object gets built, not just this POC's eight creatures. Three real Godot techniques exist, and the game actually needs a mix of them — matching the intuition that some cases morph and some don't. RECIPES.md itself already contains an example of each need without naming the techniques: Horse→Pegasus (same skeleton, add wings), Centaur (two different creatures literally glued together), and Simple Life (an arbitrary freeform blob-creature from unconstrained slots).

(a) Blend shapes / morph targets

Godot's MeshInstance3D supports per-vertex blend shapes (set up in a DCC tool or via ArrayMesh surface morph arrays), interpolated at runtime via set_blend_shape_value(). Requires identical topology/vertex count between the base mesh and every morph target — it deforms one mesh, it does not attach new geometry.

(b) Modular part attachment

Separate scenes/meshes parented onto named Marker3D/BoneAttachment3D sockets on a base skeleton. No topology constraint between parts — a horse body and a humanoid torso don't need to agree on vertex count, they just need to agree on a socket transform. This is what the object-gallery POC uses throughout.

(c) Parameterised procedural / metaball-style

Generate geometry from parameters at runtime or at creation-time — e.g. CSGCombiner3D unions of primitives whose size/position come from formula inputs, or Godot's GPUParticles-adjacent metaball-like blending for soft, mushed-together shapes. No fixed part library; the shape itself is computed.

Game need (from RECIPES.md)TechniqueWhy
Horse → Pegasus (same body, wings slot filled) Modular attachment (not blend shapes, despite looking like a "growth") The brief frames this as a morph, but implementation-wise it's cleaner as attachment: wings are a separate scene socketed at socket_back and toggled on/off. A true blend-shape approach would need the wingless horse mesh to already contain (zeroed) wing geometry, which conflicts with "the Wings slot is empty" being a real, inspectable game state. Attachment also lets wing type vary (64 possible wing elements per RECIPES.md) by swapping the attached scene — a blend shape can't swap identity, only interpolate one fixed target.
Centaur (humanoid torso + horse body) Modular attachment Textbook case for (b) — two independently-authored parts (the POC's humanoid torso, the POC's horse hindquarters) glued at one socket. Robust, and exactly how the POC's Centaur scene is built.
Gear (hats, weapons, shirts, shoes) Modular attachment No ambiguity — gear is discrete, ownable, tradeable inventory per the docs (Ingredients/Blueprints tabs), so it must be a separable object, not a deformation of the wearer.
Simple Life (2 balls mushed + stubby limbs, arbitrary weird shapes from free Body/Colour slots) Procedural/metaball-style, built from a small primitive palette This is explicitly the "no fixed pattern" case — 64×64 discoverable combinations per RECIPES.md. A parameterised generator (pick N body-blob primitives, scale/position/colour them from the filled element's trigram data) scales to that combinatorial space without hand-authoring each result. The POC's "cute basic creature" is a hand-built instance of what this generator would produce — useful as the concrete reference shape.
Same-creature colour/size/texture variation (e.g. every horse recoloured per its Colour/Texture slot) Not geometry at all — material parameters Swapping albedo_color on a shared StandardMaterial3D (or a shader uniform) covers this without touching mesh data or needing blend shapes.
Future: rigged animation (walk cycles, attack poses) if/when the game needs them Skeleton3D + attachment, not covered by this POC Out of scope here (the POC is static display), but noted because it constrains future part design: parts meant to attach to an animated base eventually need to attach via BoneAttachment3D rather than a static Marker3D, so it's worth using Godot's skeleton-attachment nodes once animation is real, rather than static markers everywhere.

4Conclusion

The three real needs in the design map to three different techniques, and no single technique covers all of them — a hybrid is correct, not a compromise. Concretely, for the object library going forward:

  1. Discrete recombination (Pegasus, Centaur, gear) — Godot Marker3D sockets + reparenting attached scenes. This is the backbone; it's what pocs/object-gallery/ implements for all eight creatures and seven gear pieces.
  2. Freeform "basic life" generation — a small procedural generator over a shared primitive palette (balls, capsules, cones), parameterised by trigram/element data, for the 64×64 Simple Life space. Not built in this POC (only one hand-authored reference instance was needed), but the palette and material conventions established here are exactly its inputs.
  3. Blend shapes — reserved for genuine same-topology deformation if it ever comes up (e.g. a creature visibly aging, or a size slider), not for part addition. Not needed anywhere in the current design.
  4. CC0 GitHub-mirrored packs — supplementary, for static environment props only, never for the creature/gear recombination system.
  5. trimesh/Blender-class pipelines — held in reserve for later batch/parametric needs (e.g. generating all 64 element-crystal shapes as a build step); not needed for hand-authored parts.