Fabricating Assets logo

Fabricating Assets

Organization
SummerEngine
fabricating-assets

Fabricate meshes with a Blender script (summer_fabricate_3d): exact-size kits, VFX meshes, post-processing.

Overview

PublisherSummerEngine
Repositorysummer
Skill namefabricating-assets
Stars
91
Forks
8
Bundled files
1
LicenseMIT
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • 1 bundled files

    Scripts, templates, and references the model can read while it works. Files are read-only and never executed.

  • Open source

    Published by SummerEngine on GitHub. Read the source before you install it.

Installation

Install the Fabricating Assets AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/SummerEngine/summer/tree/main/library/skills/fabricating-assets
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/SummerEngine/summer.git /tmp/summer
mkdir -p .claude/skills
cp -r /tmp/summer/library/skills/fabricating-assets .claude/skills/fabricating-assets
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Fabricating Assets in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Fabricating Assets on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Fabricating Assets is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Fabricating Assets

Overview

summer_fabricate_3d runs a Blender Python (bpy) script you write in the user's own installed Blender, headless and supervised by the engine, validates the .glb the script's objects were exported to, moves it under res://, waits for the import, and (optionally) instantiates it into the open scene with target_size normalization. One call: script → glb → import → scene.

It exists for a narrow slice of assets: the mesh-processing mid-tier that the engine does not have (exact booleans, bevels, UV unwrap, decimate, remesh, curve sweeps, fracture) and that generation and libraries serve badly. Everywhere else it is the wrong tool — route first.

Three facts shape every use:

  1. It is optional and detect-never-bundle. Summer does not ship, download, or install Blender. If the machine has none, the result is a structured blender_not_found with the fix, and the decision to install belongs to the user.
  2. It is blind until import. There is no viewport while the script runs. Perception comes back only through the result (objects, dimensions, warnings, skipped) and then through the normal scene loop (summer_snapshot_diff + summer_screenshot).
  3. One fabrication at a time per editor. A second call while one is in flight fails with busy. Wait for the result; never fire in parallel.

Route first — fabricate, generate, or import?

Asset classFirst routeSecondWhy
Blockout / placeholderscene-scripting primitives or CSGfabricateMust be instant and in-scene; no process spawn is justified
Generic hard-surface prop ("a barrel")assets.search → summer_import_asset (prop-model)assets.generate_3dThe free library plus target_size beats paid generation and a 2-minute wait, in a consistent style
Bespoke prop ("the artifact from our GDD")assets.generate_3dfabricateImage-to-3D is exactly what generation is for; fabricate when exact dimensions or parametric variants matter
Modular kit (walls, pipes, fences, rails that snap)fabricategenerated kit (environment-kit)Generation cannot hold dimensions and style across 30 pieces; array + boolean + bevel + one material is the classic kit workflow
Characters (rigged, animated)assets.generate_3d (character-model)libraryScripted organic modelling is the documented failure mode; fabrication has no path to competitive organics blind
Environments / terrainin-engine terrain + library set dressinggeneration for landmarksTerrain wants interactive tools; dressing wants scatter
Materials / textures / skieslibrary (summer_import_hdri, texture packs)generationFabricate only to bake a procedural material to images
VFX meshes (shatter pieces, trails, sweeps, LOD chains)fabricatein-engineBisect/fracture, curve sweeps, decimate are one-liners in bpy and absent in the engine
Post-processing a generated model (decimate / UV / bake)fabricate—The fix for generation's documented weaknesses; no other route exists
UIlibrary + 2D image generation—3D tooling is irrelevant

Fabricate wins in exactly three rows. If the request is not one of them, stop here and use asset-strategy to pick the specialist skill.

Prerequisite — the user's Blender

The engine looks for Blender 4.2 LTS or newer in this order:

  1. blender_path passed in the call (only when the user named a path — never guess one);
  2. the SUMMER_BLENDER_BIN environment variable of the editor process;
  3. Editor Settings → FileSystem → Import → Blender → Blender Path (filesystem/import/blender/blender_path, the same setting .blend import uses);
  4. PATH, the platform's well-known install locations, and ~/.summer/tools/blender-<version>/.

When none resolves, the result is failure_reason: blender_not_found with tried (every path checked) and a prescriptive error. Relay it as a one-line decision: "Fabrication needs Blender (4.2 LTS or newer) on this machine. Install it from the official Blender download page, or point SUMMER_BLENDER_BIN at an existing executable and restart the editor. Or I can generate the asset or import one from the free library instead." Then do what the user chooses. Do not install software on their behalf, and do not retry the call hoping the answer changes.

The blender_version in every successful result is a fact, not a suggestion: bpy APIs change across majors, and models skew toward older bpy from training data. When a script_error names a missing attribute or operator, check it against the version that actually ran.

The script contract

source is plain bpy code. It runs in a factory-startup Blender (no user add-ons, no preferences, online access off) with an empty scene — no default cube, light, or camera — and these names already bound: bpy, bmesh, mathutils, math, Vector, Matrix, Euler.

The script must create mesh objects and leave them linked in the scene. Nothing else. The engine's bootstrap then collects, audits, exports, and validates:

  • Do not export, do not save, do not quit. bpy.ops.export_scene.gltf, bpy.ops.wm.save_mainfile, bpy.ops.wm.quit_blender in your script break the contract and the run.
  • What exports: MESH, CURVE, SURFACE, META, FONT objects become meshes; EMPTY and ARMATURE keep hierarchy and skins; cameras, lights, probes and speakers are dropped.
  • Hidden means helper. An object hidden in the viewport or disabled for render is treated as a boolean cutter or guide: it is not exported and is listed in skipped. Use this deliberately for cutters; check skipped when a piece is missing.
  • Modifiers are applied at export (export_apply), including Geometry Nodes — the scene stays non-destructive, so do not modifier_apply by hand unless you need the result for a later step (a boolean whose output feeds a second boolean, for instance). Consequence: shape keys are dropped when modifiers exist; a warning says so.
  • Only a Principled BSDF surface survives glTF. Any other shader (Emission-only, Diffuse, custom node group) exports grey or black — a warning names the material. Build materials as Principled BSDF with constant values or Image Texture inputs.
  • Procedural Base Color is baked for you (Cycles, 2K cap, capped material count; meshes without UVs get a Smart UV Project first) and reported in baked. Procedural Metallic / Roughness / Normal / Emission / Alpha are NOT baked — set constants, or bake them to an Image Texture in your script; the warnings list tells you which channel was left procedural.
  • Axis and units: model in Blender's native Z-up, in metres; the export converts to the engine's +Y-up (dimensions in the result is already +Y-up). A 2 m wall segment is dimensions.y ≈ 2.
  • Naming: object names become node names in the imported scene. Name every object and material (obj.name = "Wall_2m_A"). The name argument names the .glb (res://assets/fabricated/<name>.glb unless out_path says otherwise) and the instantiated node; it is sanitized to [A-Za-z0-9_-].
  • Determinism: seed anything random (random.seed(7), noise textures with fixed seeds). A re-run must produce the same mesh so the loop below converges.
  • No network. Blender's online access is off; scripts that fetch anything fail. Reference images and existing models come from the project on disk (below).

Minimal template

python
# Kit piece: 2 m wall segment with a door cutout, bevelled, one material.
import bmesh

def make_box(name, size, location):
    bpy.ops.mesh.primitive_cube_add(size=1, location=location)
    obj = bpy.context.active_object
    obj.name = name
    obj.scale = size
    bpy.ops.object.transform_apply(scale=True)
    return obj

wall = make_box("Wall_2m_Door", (2.0, 0.2, 3.0), (0, 0, 1.5))

cutter = make_box("DoorCutter", (1.0, 0.4, 2.1), (0, 0, 1.05))
cutter.hide_set(True)          # hidden = helper: used by the boolean, never exported
cutter.hide_render = True

cut = wall.modifiers.new("Door", "BOOLEAN")
cut.operation = "DIFFERENCE"
cut.object = cutter
cut.solver = "EXACT"

bevel = wall.modifiers.new("Bevel", "BEVEL")
bevel.width = 0.02
bevel.segments = 2

mat = bpy.data.materials.new("KitStone")
mat.use_nodes = True
bsdf = mat.node_tree.nodes["Principled BSDF"]
bsdf.inputs["Base Color"].default_value = (0.55, 0.52, 0.48, 1.0)
bsdf.inputs["Roughness"].default_value = 0.85
wall.data.materials.append(mat)

Call it with name: "wall_2m_door", import_to_scene: {parent: "./Kit"}, no target_size (the piece is already modelled at 2 × 0.2 × 3 m — a kit that snaps must keep its authored dimensions).

The loop

  1. summer_get_project_context — confirm the engine is up and which project is bound; read projectPath if the script needs a file from the project.
  2. summer_world_snapshot — the BEFORE baseline; keep snapshot_id.
  3. summer_fabricate_3d — source, name, import_to_scene: {parent, position?}, and target_size only when the asset is not dimension-authored (a hero prop whose size you are normalizing, not a kit piece). Default max_seconds 120 covers boot + script + bake + export for ordinary pieces; raise it (up to 600) for exact booleans on dense meshes or several bakes.
  4. Read the result before looking at anything else. ok and ran; objects[] (each with vertices, faces, triangles, materials, modifiers) against what you meant to build; dimensions in +Y-up metres against the spec; skipped for pieces that vanished because they were hidden; warnings for grey-material and unbaked-channel problems; baked for what the bootstrap did to your materials; output for your own print()s. A non-zero exit_code after a validated export is a warning, not a failure — the artifact is what was verified.
  5. summer_snapshot_diff from_id:<the id> — the structural receipt: exactly one new subtree under parent named <name>, nothing else changed.
  6. summer_screenshot — look at it. target:"scene" framing:"camera" when materials or lighting matter; a preset framing for silhouette and scale checks.
  7. Iterate on the script and re-run with the same name — the .glb is overwritten in place (overwrote_existing: true), and the previously instantiated node is still in the scene: remove it with summer_remove_node before re-importing to scene, or import without import_to_scene and let the existing instance pick up the new file.
  8. summer_save_scene once the piece is right. Instantiation is one undo action in the open scene, not a save — an unsaved instance is lost when the editor closes.

Never claim a visual result without step 6. The full perception discipline is verifying-scenes.

Post-processing a generated model

Generation delivers dense triangulated geometry with poor UVs. Fabrication is the fix:

python
import os
src = os.path.join(PROJECT_DIR, "assets", "generated", "goblin_statue.glb")   # PROJECT_DIR from summer_get_project_context.projectPath
bpy.ops.import_scene.gltf(filepath=src)
meshes = [o for o in bpy.context.scene.objects if o.type == "MESH"]
for o in meshes:
    bpy.context.view_layer.objects.active = o
    o.select_set(True)
    dec = o.modifiers.new("Decimate", "DECIMATE")
    dec.ratio = 0.25
    bpy.ops.object.mode_set(mode="EDIT")
    bpy.ops.mesh.select_all(action="SELECT")
    bpy.ops.uv.smart_project(angle_limit=math.radians(66), island_margin=0.02)
    bpy.ops.object.mode_set(mode="OBJECT")

Substitute the real absolute project path for PROJECT_DIR (a string literal built from summer_get_project_context → projectPath); scripts have no res://. Write the result to a new out_path (res://assets/generated/goblin_statue_lod1.glb) so the original stays for comparison, and compare objects[].triangles before and after in the result.

Shatter fragments without add-ons

Factory startup disables add-ons, so cell-fracture operators are not available. Cut with bmesh.ops.bisect_plane in a loop over random planes, bmesh.ops.split_edges / separate by loose parts, and name each fragment Shard_00, Shard_01, … — the imported scene then carries one MeshInstance3D per shard, ready for a RigidBody3D wrap in a summer_run_script pass.

Failure taxonomy — read failure_reason, then act

failure_reasonWhat happenedDo
engine_lacks_opThis engine build predates FabricateMesh (nothing was sent)Route to assets.generate_3d, assets.search / summer_import_asset, or summer_run_script blockout geometry; tell the user an engine update enables fabrication
blender_not_foundNo usable Blender executable (see tried)Relay the one-line decision above; never guess a path or install anything
blender_launch_failedThe executable exists but did not start (permissions, broken install, wrong architecture)Show the error and output tail to the user; a different blender_path or a reinstall is their call
script_errorYour bpy raised (traceback_tail, script_line, blender_version)Fix the named line against the reported version; script_line maps to your source
timeoutThe child exceeded max_seconds (echoed) and was killed; nothing was importedRaise the budget (≤ 600), or split — one piece per call, fewer bakes, coarser booleans
export_emptyThe script left no exportable objectEverything hidden? Not linked to a collection? Wrong type (a light, a camera)? Check skipped
export_failed / export_missingThe exporter failed or wrote nothingRead errors — usually a material or modifier the exporter cannot handle; simplify
bootstrap_errorThe engine's own bootstrap failed (not your script)Report it verbatim as a bug; do not work around it
import_failedThe .glb is at out_path but the editor did not import itRead the importer's message with summer_get_console; often a zero-face mesh or an oversized texture. Fix and re-run, or summer_instantiate_scene the file after a manual rescan
instantiate_failedImported fine; instantiation into the open scene failed (bad parent, no scene open)The asset is in the project — open the right scene and summer_instantiate_scene it with target_size
busyAnother fabrication is in flightWait for that result; never parallelize
cancelled / shutdownThe run was cancelled or the editor closedRe-run when the editor is back
rejected_identityThe engine switched projects mid-runsummer_get_project_context to rebind, then decide whether to re-run
bad_argsMalformed out_path, target_size, or empty sourceFix the argument; nothing was sent

Every failure leaves the project untouched except import_failed / instantiate_failed, which are honest about the .glb they did write. A no_rewind_point: true on any result means no SummerGit checkpoint exists for the run — say so before doing more destructive work.

Licensing and attribution

  • Blender is the user's. Summer runs the executable they installed as a separate process and talks to it only through arguments, files, and the exit code. Nothing in Summer links against Blender or imports bpy; the small export bootstrap the engine writes to a scratch directory is a separately licensed GPL file precisely because it does. Do not move project logic into bpy scripts expecting it to stay proprietary.
  • Output is unencumbered. Meshes made with Blender belong to the user; the .glb in their project carries no Blender licence obligation.
  • Scripts you write here are created on the user's machine and never distributed by Summer. If you adapt a bpy snippet from elsewhere, respect its licence — prefer your own code or CC0 sources, and record the origin in .summer/memory/decisions/ when it matters for the project.
  • Trademark. "Blender" is a trademark of the Blender Foundation. Refer to it factually as the dependency ("requires Blender"); never describe the feature as powered by, built on, or branded with Blender, and never use its logo. Summer's name for this capability is mesh fabrication.
  • Imported library assets keep their own licences (assets.search results carry license); fabrication does not change that.

Red Flags — STOP

Red flagReality
Fabricating a barrel, a crate, a chairLibrary first, generation second. Fabricate is for kits, VFX meshes, and post-processing
Fabricating a character or creatureScripted organic modelling is the documented failure mode; assets.generate_3d with rigging
A script that calls export_scene.gltf, saves, or quitsBreaks the contract; the bootstrap exports
A material that is not a Principled BSDFExports grey; the warnings list said so
Procedural roughness or normal maps left unbakedNot baked automatically — set constants or bake in the script
target_size on a kit pieceDestroys the authored dimensions the kit snaps on
Two fabrications in flightbusy; one at a time per editor
Guessing a blender_pathOnly the user knows where their Blender is; use the resolution order
Installing Blender for the userNever. Relay the decision
Claiming the piece looks right without a screenshotThe fabricator is blind; only step 6 sees
A hidden object that was supposed to exportHidden means helper; unhide it or check skipped
Retrying the same script after timeoutRaise the budget or split the job; the same oversized script times out again

Related skills:

  • asset-strategy — the route decision for every "I need a [thing]".
  • environment-kit, prop-model, character-model — the generation and library specialists fabrication defers to.
  • scene-scripting — in-scene geometry, placement loops, and wrapping fabricated pieces in bodies and collisions.
  • verifying-scenes and verification-before-completion — the evidence discipline after import.

From a shell

No Summer MCP tools in this session? Run each one as a command; when summer --version is missing or below 4.0, use npx -y summer-engine@latest in place of summer. Fields are flags in kebab-case (--scene-path res://main.tscn) or one --input '<json>', and summer ops describe <op> prints the exact input. The summer-cli skill has the rest.

In this skillCommand
assets.generate_3dsummer assets generate-3d
assets.searchsummer assets search
summer_fabricate_3dsummer engine fabricate-3d
summer_get_consolesummer engine get-console
summer_get_project_contextsummer engine get-project-context
summer_import_assetsummer engine import-asset
summer_import_hdrisummer engine import-hdri
summer_instantiate_scenesummer engine instantiate-scene
summer_remove_nodesummer engine remove-node
summer_run_scriptsummer engine run-script
summer_save_scenesummer engine save-scene
summer_screenshotsummer engine screenshot
summer_snapshot_diffsummer engine snapshot-diff
summer_world_snapshotsummer engine world-snapshot

Bundled files

The model reads these on demand while the skill is loaded. They are exposed as readable files and are never executed.

Frequently asked questions

What does the Fabricating Assets AI skill do?

Fabricate meshes with a Blender script (summer_fabricate_3d): exact-size kits, VFX meshes, post-processing.

Why use Fabricating Assets on TypingMind?

Because you install it once and use it with any model. Fabricating Assets is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Fabricating Assets in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/SummerEngine/summer/tree/main/library/skills/fabricating-assets. TypingMind reads its SKILL.md and bundles its files and installs it as a skill you can enable per chat.

Which AI models can use Fabricating Assets?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Fabricating Assets?

As many as you like. As long as a model supports skills, you can use Fabricating Assets with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Fabricating Assets AI skill free?

Yes. It is published on GitHub by SummerEngine under the MIT license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇