Blitz3D+ Guides

Reusable Resources and Materials

A .world file places objects and owns scene settings. A .material file describes a reusable appearance. A .prefab groups an owned reusable entity hierarchy. A .physics file describes reusable bodies, colliders and joints. A .particles file describes an authored group of emitters; see Authored particle effects. .environment and .postfx store world and camera appearance presets. .sound and .audiomix store source defaults and explicit mixer presets. These are V1 formats; the development reader does not offer an older world schema or a migration mode. All commands on this page require Extended mode.

See Saving and exporting resource projects for Save All, recovery journals, explicit export roots and live snapshot limits.

Shared definitions and local appearances

This complete material document describes blue Standard paint:

{
  "format": "blitz3d.material",
  "version": 1,
  "id": "paint.blue",
  "name": "Blue paint",
  "assets": [],
  "definition": {
    "model": "standard",
    "color": [0.15, 0.35, 0.8, 1],
    "properties": {"metallic": 0, "roughness": 0.3}
  }
}

Declare it in a world's assets array, then bind its alias on a model component. A second object can override selected values:

{"id":"paint","kind":"material","loading":"required","source":"paint.material"}

{"type":"model","primitive":"sphere","materials":[
  {"slot":0,"asset":"paint","overrides":{"color":[0.8,0.15,0.1,1],"properties":{"roughness":0.8}}}
]}

Overrides replace authored values on that instance. They do not modify the shared file or neighbouring objects. Removing an override reveals the shared value. Runtime brushes have independent parameters and texture transforms while sharing image and shader resources. Editing a brush with runtime commands does not rewrite the saved descriptor.

For a complete two-object scene, open shared-materials.world in the World Editor or run SharedMaterials.bb. The standalone resource example creates, edits, saves and loads a material through the public API.

Embedding, dependencies and paths

An asset uses exactly one of source or inline. To embed a descriptor, put its complete resource document in inline and omit source. The resource schema is identical in both forms. Raw models, textures, heightmaps, sounds and shaders remain external files.

Each descriptor's assets array declares its own local aliases. Dependency entries use id, kind, a source or inline document, and optional import options. They do not have a loading policy: preparation inherits the strongest policy required by their consumers. Paths are relative to the declaring file; inline descendants use that file's directory. Extraction and Save As rebase paths while preserving resource IDs. An optional expectedId detects a replaced descriptor. Duplicate identities from different files and dependency cycles fail validation.

Shader options.configuration must be omitted or empty. Select the program in .b3shader and configure its material parameters in .material. Nonempty configurations are rejected.

Material models and values

  • classic: colour, alpha, shininess, supported brush effects and texture slots 0 through 7.
  • standard: the native Standard material properties, alpha mode/cutoff and named texture roles.
  • shader: exactly one shader.asset alias or shader.builtin name, with typed float, int, four-component vector or colour parameters and named textures.

Colour values are linear RGBA floats from 0 to 1 with straight alpha. Rotations use degrees. A texture binding stores asset, optional frame, nonzero two-component scale, offset, rotation, coordinates (0 or 1), blend (0 to 5) and colorSpace. Standard baseColor, emissive, sheenColor and environment roles use srgb; its data maps use linear. Classic/custom bindings use linear; custom shader code controls further colour conversion. An explicit encoding must match the role.

renderState selects blend (auto, opaque, alpha, multiply, add), cull (auto, back, none) and depth (default, test-write, test, none). Shader requirements still apply: incompatible explicit state fails validation. MaterialPropertySchema reports the Standard property's component count, range and defaults. MaterialShaderSchema reflects the prepared shader's actual parameters and texture stages. Shader names are case-insensitive.

Numbered slots and changed model imports

Slot 0 applies to the whole model hierarchy. Positive slots address one-based surfaces in depth-first model/node order. All-surfaces and numbered bindings cannot overlap. Runtime validation checks that every addressed slot exists and has a compatible mapping at every LOD.

A positive slot on an imported model also requires modelRevision: the lowercase SHA-256 value returned by WorldAssetImportRevision for that ready model asset. It covers the importer contract, import options and actual source inputs. Changes to geometry or textures invalidate this mapping; moving an intact asset folder preserves it. A stale pin makes the next world load fail with a reassign diagnostic. Existing worlds retain their old resources. Slot 0 and primitive bindings do not use this field.

In the World Editor, open a model's Materials tab. Validate assignment prepares an isolated current model and material. Apply / Rebind records the reviewed mapping and makes the material required in one document transaction. To repair a changed import, review its current geometry in Assets and explicitly rebind. Validation does not lock source files indefinitely; a later edit can invalidate the saved pin on the next load.

Reusable physics and world-owned contexts

A .physics definition contains named physical materials, one or more bodies, their shapes, and optional joints between bodies in the same assembly. Body types are static, kinematic and dynamic. Shapes are box, sphere, capsule, convex hull, triangle mesh or heightmap terrain. Mesh and terrain colliders require static bodies. Each body has at least one shape. A shape may name a physical material with friction and restitution; density and sensor state are shape properties.

Distances and dimensions use metres, mass uses kilograms derived from density, time uses seconds, and hinge angles and angular speeds use radians. size gives the full box dimensions, sphere diameter, capsule diameter and total height, or terrain width, height and depth. Shape offsets, hull points, mesh points and joint anchors use the target entity's local space. A body target may have a positive uniform world scale and rotation. Nonuniform or sheared transforms fail loading. The loader scales dimensions, offsets and authored geometry when it cooks the native collider. A body may declare position and a unit rotation quaternion [x,y,z,w]; these compose with its target's authored transform before construction. Each body needs a distinct target entity.

Initial linearVelocity is a world-space metres-per-second vector; angularVelocity is a world-space radians-per-second vector. Distance lengths and slider limits/speeds scale with the first joint body's target; hinge limits and speeds remain angular values.

{"id":"crate","kind":"physics","source":"crate.physics","loading":"required"}
{"id":"crate-entity","components":[{"type":"model","primitive":"cube"},
  {"type":"physics","asset":"crate"}]}

A physics component places one assembly. Each body targets the component's entity by default. For a multi-body assembly, targets maps body IDs to entity references, for example {"arm":{"entity":"arm-visual"}}. The world can also declare a physics-joint component to connect bodies from independent assemblies. Its bodyA and bodyB contain the physics component entity ID and local body ID. The example in physics-showcase.world shows a compound body, hinged assembly and cross-assembly distance joint.

The world owns one explicit physics context for its authored assemblies. settings.physics.gravity sets its gravity (default [0,-9.81,0]). After the world is ready, call WorldPhysicsContext to obtain the context, then StepPhysics context,1.0/60.0,4 from your fixed-step loop. UpdateWorld still processes classic collision and animation, but does not step this context. Code can retrieve an authored body or joint using WorldPhysicsBody and WorldPhysicsJoint. These handles belong to the world and become invalid when it is freed.

Loading constructs bodies and joints in a staging world. A missing target, invalid body reference, unsupported transform or native cooking failure fails the entire load; no incomplete world is published. In the World Editor, the Scene view draws native collider and joint overlays. Play physics steps its preview at a fixed 60 Hz; stopping rebuilds the preview from the saved authoring snapshot. The playable ReusablePhysics.bb sample demonstrates the same rules.

For a UI-only authoring path, follow Creating a physics scene from a new world to a saved floor, falling box and scene joint. The Physics definition window edits typed body state, shapes, physical materials, internal joints and exact geometry; Save validates a cooked candidate world. The Scene Physics pane attaches a single-body asset, places a multi-body assembly with a reviewed distinct target for each body, and offers Make Local or Save as New Physics for one selected consumer. Shared edits list affected consumers. Live DebugWorld sessions expose physics for inspection only.

Editing and saving

Use Edit / New Material or Edit Material in Assets. The inspector supports typed values, textures, live previews, Source / Repair, external Save, Save As / Extract and Embed in World. Embedded data reaches disk when the world is saved. Edit Shared Asset changes the shared definition. Override This Instance marks overridden values; Reset Override removes one override. Make Local creates a new resource ID and retargets the selected binding, preserving its model pin. Live debugging sessions currently disable material authoring.

Public document handles retain authored data independently of runtime worlds. ResourceDocumentJson returns a caller-owned copy; editing it alone does not change the document. Commit with ReplaceResourceDocumentSource or ApplyResourceDocumentEdit, passing the current Long revision. Invalid or stale edits leave the document unchanged. A typed transaction looks like this, with revision set from ResourceDocumentRevision:

{"protocol":"blitz3d.resource-document-edit","version":1,"revision":0,
 "operations":[{"op":"set-material-property","group":"properties","property":"roughness","value":0.4}]}

The other operations are set-name, replace-definition and replace-assets, each with a value. Property groups are properties, parameters, renderState and textures; omit group for colour, shininess, effects, alphaMode or alphaCutoff. The entire resulting document is validated before commit.

ValidateResourceDocument returns an owned JSON report containing valid, errorCount and diagnostics. It does not return a Boolean. Repair mode retains invalid source for editing, but invalid data cannot be saved as a valid resource or instantiated. Save detects files changed since open. Save As to an existing different target requires its observed SHA-256 digest. A child extraction creates a new file and dirties its parent; it does not commit a multi-file save. Free all returned JSON handles and resource documents when finished.

The material inspector prepares a fresh preview on Save, including after a filename dialog, so changed shader and texture inputs are validated again. External material saves use SaveResourceDocumentWithWorldEdit to validate the proposed source against scene aliases and nested prefab bindings before replacing the resource file and committing the in-memory world edit. Rejected bindings, stale revisions and destination conflicts preserve both documents and the destination. The world remains dirty until Save World. This coordinates one resource file with one in-memory world edit; the general multi-file Save All workflow is separate. Runtime import and shader validation still require async preparation.

The inspector supplies its ready material preview to the commit operation. Its actual source files must still match preparation and remain guarded during the commit. Each affected instance's effective parameters are checked against the prepared shader, including bindings inside prefabs. Embedded material and instance-override edits use ApplyResourceDocumentWorldEdit for the same validation, changing only the in-memory world. Programmatic callers may omit the preview argument for authored-data validation alone; imported mesh slot mappings still require a prepared model.

Preparing a resource

LoadResourceDocumentAsync snapshots the document into an ordinary world. The document can be edited or freed immediately afterwards. Poll WorldReady and service UpdateAsyncLoads; inspect WorldLoadError on failure. Find the resource with alias resource. For materials, WorldAssetMaterial returns an independent brush. For prefabs, the placement root is named instance. Release the snapshot world with FreeWorld. Returned brushes remain usable after the world is freed.

Native prefabs

A prefab has one root and stable local entity and component IDs. Omitted component IDs default to their type; IDs on one entity must be unique. Labels and array order do not affect identity. Nested placements use the same prefab component as a world. Saving retains the placement and never saves its generated children alongside it.

Declare typed inputs in definition.inputs, for example {"id":"paint","type":"asset","kind":"material","required":true} or {"id":"target","type":"entity"}. Inputs are required by default. Component inputs also require a kind, such as light. On the placement, bind inputs.paint to {"asset":"blue"} and inputs.target to {"entity":"anchor"}. Nested definitions forward inputs with {"input":"paint"}. Model components consume model inputs through assetInput; material bindings use input instead of asset.

A part selector is {"instances":["nested-placement"],"entity":"body","component":"mesh"}. Omit instances for the current scope and component for an entity target. References inside a definition never search the outer scene. Missing required inputs and invalid types fail before the world becomes ready. For standalone preparation, a prefab with required inputs must be placed in a world supplying those bindings; a resource-only snapshot cannot invent them.

A placement's overrides array contains target, property and value. For example, {"target":{"entity":"bulb","component":"light"},"property":"range","value":25}. Entity overrides cover name, enabled, visible and position/rotation/scale. Component overrides cover supported camera/light/collision settings, model shadows, cullRange and lodTransition. A model material override uses a material property patch and optional slot (zero by default). Inner overrides apply before enclosing overrides. Structural changes require editing the shared source or Make Local.

An attachment component supplies a typed target and an optional bone name or hierarchy path. Its local transform is relative to that target. Bone targets require an animated model and an existing, unambiguous bone; validation finishes after model preparation. Parenting and ownership cycles fail the load. Static model lods contains {"asset":"low-mesh","distance":20} entries in strictly increasing distance order; animated and morphed LOD meshes are rejected.

CopyEntity copies owned parts, remaps internal inputs and shares immutable resources. External input targets remain borrowed. FreeEntity and FreeWorld release owned parts even when they have been reparented. They do not free borrowed input targets. EntityOwner, CountOwnedEntities and GetOwnedEntity inspect ownership; FindPrefabPart uses stable local identity. PrefabInputsBound detects required targets that have since been freed. A copy with an invalid required input, or an external binding into another world, is rejected.

In the World Editor, expand a prefab to inspect its owned parts, then use the Prefab inspector tab. Instance edits change the placement's bindings and overrides. Open shared source edits the containing descriptor and validates its consumers in the current world before saving. Make Local creates ordinary authored parts with fresh IDs and the effective overrides; Ctrl+Z undoes it. Save as New Prefab uses a new identity and retains shared media. External scene targets become typed inputs instead of leaking into the saved template. Shared-source disk saves are separate from the world's undo history.

From code, CreatePrefabDocument(world_document,entity_id$,file$) captures a subtree as a dirty resource document; SaveResourceDocument writes it. World edit operations entity.duplicate-subtree (id/newId) and prefab.make-local (id) use ordinary revision-checked transactions.

Try the nested prefab scene and the complete authoring, copy and free example.

Validation and schemas

b3dworldc scene.world paint.material object.prefab validates descriptors and their dependency graph. --no-files checks structure without opening external dependencies. Runtime loading additionally checks shader reflection and imported surface mappings.

The installation's world directory contains world, material, prefab and shared resource JSON Schemas. The common schema is generated by b3dworldc --schema. Use the schemas for structural authoring assistance and the native validator for byte limits, duplicate keys/IDs, dependency and reference checks, hierarchy rules and cross-property constraints. Descriptor closures allow 32 levels, 4096 documents and 64 MiB of source text.

World and resource command reference · Guides