Mawu · Features

Mawu Studio: Creation Tools

A focused page within the Mawu Features documentation. The full map and every sibling page live in the Features hub.

6sections12 minread1diagram

On this page

Mawu Studio is where a player stops being a citizen of someone else's realm and becomes a world-maker. It is the tiered creation funnel V7 promises — "build the world, don't just play it" — spanning premium UE Editor authoring, an in-realm builder you use while standing inside a running world, a no-code-to-code scripting ladder, and AI-assisted generation, with every tool emitting the same unit of currency: an Ixchel layer that composes into a realm on join. Where the Ixchel sandbox page covers how untrusted creator code is run safely, and the Abundantia page covers how a finished realm is distributed and paid for, this page covers the step between them: what a creator actually makes, with what tools, and what comes out the other end.

It carries a particular burden of proof, because Mawu Studio is the V7 surface most tempting to describe richly and ship thinly. So this page follows the code. The strongest, automation-covered work is the in-realm builder (MawuBuilder in V7/ue/) and the realm-side geometry it drives; the scripting and AI-creation surfaces are real gates and compile-targets with honestly-labelled seams; the asset-budget linter is shipped and tested; and the heavy DCC asset pipeline is named-but-absent. For the full feature scope this slots into, start at the hub: ../V7_features.md.

What ships, honestly#

The V7 monolith (features§"Mawu Studio — Creation Tools") describes a four-tier funnel; the tree implements it unevenly, and it is worth stating the split up front.

  • The in-realm builder is real C++ and automation-covered. MawuBuilder's UMawuBuilderPlacementLibrary (MawuBuilderPlacement.h:155) validates grab-and-place edits across eight operation kinds (block / voxel / CSG union·subtract·intersect / model / sculpt / UV-project), tracks desktop-gizmo vs. VR-grab parity, snaps to grid, bounds-checks placement, and publishes a validated FMawuRealmLayer — a genuine Ixchel layer with a content hash.
  • Builder operations drive real geometry, not just enum tags. Every modeling op maps to a UE5 Geometry Script call inside AMawuComposedRealmActor::BuildProceduralPrimitive (MawuComposedRealmActor.cpp:164) — voxel solidify, mesh booleans, Perlin sculpt displacement, planar UV projection — producing real triangle/vertex counts and watertight solids, asserted by three V7 automation tests.
  • Scripting compiles to one canonical target — as a model. Moremi lowers both a visual-logic graph and TypeScript to a shared canonical IR against one WASM compile target (compile_mawu_studio_visual_logic_to_wasm / _typescript_to_wasm), and a publish linter rejects a layer that references a missing asset. The compile step is a canonical-IR lowering and line parser, not a production TS→WASM toolchain; treat it as the typed contract, not a compiler.
  • AI-assisted creation is a real policy gate with a fail-loud backend. evaluateMawuStudioGenerationPolicy (mawu-studio-ai-creation.ts:274) enforces Isis policy and Sophia grounding; runMawuStudioAiCreation returns backend-not-configured rather than fabricating an artifact when no real generation model is injected. The gate is genuine; the diffusion model is an injected seam.
  • The asset-budget linter is shipped and [x]. lint_mawu_studio_asset_budget flags total and per-category byte overruns, naming offending assets largest-first, with an eval pinning a 17-vs-16-MiB overrun and a clean pass.
  • The web Studio is two pages. apps/oshun/web/src/app/mawu-studio/ ships accessibility/ and localization/ route shells over real evals; the full builder/browser web UI the monolith promises is product surface, not committed code.
  • The DCC asset pipeline is absent. FBX/glTF/USD/Alembic import, photogrammetry/splat ingest, and Nanite/LOD auto-optimization (§14) have no code in V7/ue or any V7 library. Cite the in-realm builder for geometry, not an import pipeline.

The creation tools#

The four-tier funnel#

The product shape is a creation funnel from "make it cooler" to "modify the Rayleigh-scattering coefficient": UE Editor authoring for premium worlds and cinematics, the in-realm builder for in-context construction, visual logic → TypeScript for behaviour, and AI-assisted generation across the lot. The funnel's organizing rule, inherited from the V5 creator suite and the V3 Lilith Studio split, is that every tool emits an Ixchel layer and every layer passes the same publish linter before it can ship — referential errors block publish rather than surfacing as a runtime crash on some other player's machine.

The in-realm builder#

This is where the code is strongest, because in-context building has a sharp, testable burden: an edit placed in a live world must be validated, snapped, bounded, and turned into a composable layer. FMawuBuilderPlacementRequest (MawuBuilderPlacement.h:29) is one edit — a PrimitiveId, a realm primitive Kind (cube/plane/pillar/marker), an EMawuBuilderOperationKind (MawuBuilderPlacement.h:16: Block, Voxel, CsgUnion/CsgSubtract/ CsgIntersect, Model, Sculpt, UvProject), the EMawuBuilderInputSurface it was authored from (DesktopGizmo or VrGrab), a transform, extents, a grid size, a placement bound, a colour, and a material role.

EvaluatePlacement (MawuBuilderPlacement.cpp:163) is the per-edit gate: it rejects a missing id, a non-positive grid or bound, snaps each axis with FMath::GridSnap when bSnapToGrid is set, runs the primitive's own IsValid, and rejects anything beyond MaxDistanceFromOriginCm from the origin. Crucially, it sets the emitted primitive's realm operation via MapBuilderOperationToRealm — voxel, CSG, sculpt, and UV-project map to their realm-geometry counterparts, while a plain Block and an imported Model map to None (the legacy BasicShape path). That mapping is what makes a builder edit drive geometry, not merely classify it, and it has its own automation test (V7.Mawu.Builder.GeometryOpsDriveRealmOperationKind).

PublishIxchelLayer (MawuBuilderPlacement.cpp:222) is the layer gate. From a FMawuBuilderLayerDraft (a realm id, an Ixchel layer id defaulting to ixchel.builder.draft, an author account, a priority, and a list of placements) it re-evaluates every placement, accumulates desktop/VR authoring counts, tracks which operation families were exercised, builds a canonical payload, and stamps a stable content hash (StableBuilderContentHash — a deterministic FNV-1a-derived 256-bit digest emitted in the sha256: content-hash shape; the authoritative cryptographic hashing happens server-side in the Ixchel content store). It then enforces three optional coverage gates a serious realm can require: bRequireDesktopVrParity (every edit reproducible on both input surfaces), bRequireBlockVoxelCsgCoverage, and bRequireModelingSculptingUvCoverage. The result is a validated FMawuRealmLayer ready to compose — the same layer type a realm's lock file pins.

What keeps the in-realm builder task [ ] despite this real code is the live loop: there is no networked VR input device path and no publish-into-a-running- session that other clients compose on join. The placement-and-publish library and its geometry are real; the end-to-end "build inside a running realm and watch it appear for everyone" flow is the integration target, consistent with the intake-and-serve seam the Ixchel architecture page names.

From a builder edit to real geometry#

A placed primitive whose OperationKind != None is realised as a genuine UE5 UDynamicMesh by AMawuComposedRealmActor::BuildProceduralPrimitive (MawuComposedRealmActor.cpp:164). It appends a subdivided base box (UGeometryScriptLibrary_MeshPrimitiveFunctions::AppendBox, 4×4×4 so deformations have vertices to move) and then dispatches on the op: Voxel runs ApplyMeshSolidify (a sparse-voxel remesh); the three CSG kinds build an overlapping tool box and run ApplyMeshBoolean with Union/Subtract/Intersection; Sculpt runs ApplyPerlinNoiseToMesh; UvProject runs SetMeshUVsFromPlanarProjection. It refuses to ship an empty mesh, reads back real triangle and vertex counts, and tests watertightness with GetIsClosedMesh. The composition report (FMawuCompositionReport, MawuRealmLockTypes.h:106) folds these into ProceduralTriangleCount, ProceduralVertexCount, and bProceduralMeshesClosed.

This is automation-covered three ways (MawuTests/Private/MawuRealmGeometryTests.cpp): V7.Mawu.Realm.GeometryScript.ProducesWatertightVoxelAndCsgMeshes asserts four ops become four procedural meshes with real triangles and a watertight result and zero static BasicShape fallbacks; ...RealisesSculptAndUvOps proves the sculpt and UV ops produce real geometry; and the builder-wiring test confirms each builder op drives the expected realm OperationKind. The geometry is not a placeholder — it is the literal proof that a builder edit becomes a mesh.

Visual logic and TypeScript, one compile target#

The scripting ladder lowers two on-ramps to one target. MoremiMawuStudioScriptCompileTarget::shared_v1() (moremi-realm-server/src/lib.rs:1047) names it precisely: wasm32-wasip2-component/studio-script-v1, WIT world ixchel:studio/script@1.0.0, Scripted sandbox tier, entry callback mawu_studio.on_event. compile_mawu_studio_visual_logic_to_wasm (:2498) validates a node-and-edge graph (no empty graph, no duplicate node, no dangling edge) and lowers each node to a canonical MoremiMawuStudioScriptOperation; compile_mawu_studio_typescript_to_wasm (:2548) lowers recognised API lines to the same IR. Both produce a MoremiMawuStudioCompiledScript targeting the same WIT world and tier — so a no-code trigger and an equivalent TS script land on the same sandbox surface. The honest caveat (and why the task is [ ]): this is a canonical-IR lowering plus a line parser, not a real TypeScript→WASM compiler; the emitted .wasm name is derived, and the actual sandboxed WASM the Moremi server runs is the Wasmtime path documented on the Ixchel architecture page, not produced here.

AI-assisted creation, gated and fail-loud#

@isis/three-d-pipelines's mawu-studio-ai-creation.ts is the generation gate for the four AI tools (MAWU_STUDIO_AI_CREATION_TOOLS: text-to-3d, text-to-texture, text-to-world, text-to-npc). evaluateMawuStudioGenerationPolicy (:274) is a real Isis-policy + Sophia- grounding check: it emits typed diagnostics for a missing creator or realm, an unsupported tool, an empty or over-long prompt, a disallowed prompt term, an unapproved model id, missing required Sophia grounding sources, and missing attribution/licence on a cited source. Only when the policy accepts does runMawuStudioAiCreation (:717) generate — and absent an injected backend it returns backend-not-configured rather than fabricating an artifact, the zero-stub fail-loud seam. When a backend is supplied (the reference procedural backend at :664 for tests), every artifact carries a buildAttribution bundle — generatedBy: isis, groundedBy: sophia, a prompt SHA-256, and per-source licence/attribution — so provenance is authored in alongside the asset, not bolted on. This is the same posture the V3 Lilith Studio takes on generative costume, generalized to world content.

Upstream of generation sits the Forge Assist co-creator (@maya/forge-assist), the AI that writes realm scripts. Its CapabilityPolicy (capability-policy.ts) scans generated source for oshun.invoke("…") and rejects, with named violations, any artifact that invokes an undeclared capability, declares a capability outside the realm allowlist, or touches a platform-owned namespace (identity, economy, safety) — "there is no declaration that makes a realm script mint currency." ForgeAssistService (forge-assist.ts:141) returns a ForgeArtifactProposal (declared capabilities, a source SHA-256, model provenance) only after it clears that policy, so a malicious proposal never reaches the sandbox.

The authoring workflow#

The workflow is a pipeline: an edit becomes a layer, the layer is linted and budget-checked and accessibility-checked, and a clean layer becomes a resource manifest the realm composes. Two linters gate publish.

lint_mawu_studio_layer_publish (moremi-realm-server/src/lib.rs:2600) is the referential gate. It rejects an empty layer id, a layer with no compiled scripts, a script whose target/tier doesn't match the shared compile target (ScriptTargetMismatch), and — the §14 "Done when" criterion — a script that references an asset the layer never declared (MissingAssetReference). When the diagnostics are empty it mints a MoremiResourceManifest (a Content resource carrying the declared assets, the compiled WASM script entries, and the exported event callback) — the same manifest shape the Ixchel runtime resolves and sandboxes.

lint_mawu_studio_asset_budget (:2712, the shipped [x] task) is the weight gate. A realm declares a MoremiMawuStudioRealmAssetBudget (:1329) — a total byte ceiling plus optional per-category sub-budgets — and the linter sums a layer's sized assets, emits TotalBudgetExceeded and CategoryBudgetExceeded diagnostics naming each offending asset largest-first with human-scale MiB sizes, and passes a within-budget layer clean. Its eval (run_moremi_mawu_studio_asset_budget_eval, :2854) and test (mawu_studio_asset_budget_eval_flags_overrun_and_passes_within_budget, :13198) pin a 17-vs-16-MiB total overrun (both assets named), an 8-vs-6-MiB texture-cap overrun, and a clean 9-MiB layer.

Finally the accessibility floor is an eval, not a hope. runV7MawuAccessibilityEval (@v7/contracts, accessibility-eval.ts:182) and lintV7MawuStudioAccessibilitySurface (:233) check three required surfaces — mawu-studio-builder, abundantia-browser, default-realm — against five rules: voice/radio text-and-visual parity, colourblind-safe provenance diff, keyboard/gamepad builder parity, a scalable-UI floor, and a reduced-motion floor. The web Studio's accessibility/ page renders this report live; the linter is what guides an author to keep the floor intact. (Honestly: the eval is real TypeScript over a fixture; the builder/browser UI it scores is largely the two-page seam above, which is why the accessibility task sits [~].)

flowchart TD BRIEF["Creator brief"] --> ONRAMP{"on-ramp"} ONRAMP -->|in-realm builder| PLACE["EvaluatePlacement<br/>snap + bounds + op→realm map"] ONRAMP -->|visual logic / TS| COMPILE["compile_*_to_wasm<br/>shared canonical IR"] ONRAMP -->|AI tool| GATE["evaluateMawuStudioGenerationPolicy<br/>Isis policy + Sophia grounding"] GATE -->|accepted, no backend| FAILLOUD[["backend-not-configured<br/>(no fabricated artifact)"]] GATE -->|accepted + backend| ATTR["buildAttribution<br/>prompt hash + source licences"] PLACE --> LAYER["FMawuRealmLayer / Ixchel layer<br/>content hash"] COMPILE --> PUBLINT["lint_mawu_studio_layer_publish"] ATTR --> LAYER LAYER --> PUBLINT PUBLINT -->|MissingAssetReference / target mismatch| REJECT[["publish blocked, named errors"]] PUBLINT -->|clean| BUDGET["lint_mawu_studio_asset_budget"] BUDGET -->|over budget| WARN[["assets named largest-first"]] BUDGET -->|within budget| MANIFEST["MoremiResourceManifest"] MANIFEST --> IXCHEL{{"Ixchel: resolve + sandbox + compose"}} IXCHEL --> CLIENT["AMawuComposedRealmActor::ApplyLockFile<br/>renders pinned closure"]

What gets created#

Everything a creator makes lands as one of a small set of composable artifacts, which is what lets a realm pin and reproduce exactly what it runs:

  • An Ixchel layer (FMawuRealmLayer) — the unit the in-realm builder emits: an id, a priority, a content hash, and a list of realm primitives, each carrying the OperationKind that drives its Geometry Script realisation.
  • A resource manifest (MoremiResourceManifest) — what a linted script layer becomes: declared assets, compiled WASM script entries, a sandbox tier, and exported callbacks, ready for capability-gated execution.
  • A compiled script (MoremiMawuStudioCompiledScript) — the canonical-IR lowering of a visual-logic graph or a TS source against the one studio target.
  • An attributed AI artifact (MawuStudioAiCreationArtifact) — a generated mesh/texture/world-layer/NPC profile with a media type, an Isis provenance bundle, and Sophia source attributions, or an honest backend-not-configured outcome.

These compose on the realm side: the Moremi server resolves and pins a lock file, and AMawuComposedRealmActor::ApplyLockFile (MawuComposedRealmActor.cpp:27) renders the pinned, content-addressed closure on every joining client — the same composition path the Ixchel architecture page documents end to end.

Edge cases and honest seams#

  • A builder edit out of bounds is rejected, not clamped. EvaluatePlacement refuses a primitive beyond MaxDistanceFromOriginCm with a named reason; a missing id or non-positive grid fails the same way.
  • A coverage requirement fails the whole publish. If a draft sets bRequireDesktopVrParity and one edit lacks VR parity, PublishIxchelLayer returns unpublished with the parity reason — all-or-nothing, like V3's premium dual-authoring parity.
  • A script referencing a missing asset cannot publish. The publish linter emits MissingAssetReference naming the script and the asset; no manifest is minted.
  • AI generation fails loud without a model. No injected backend yields backend-not-configured, never a fabricated mesh — the zero-stub rule made mechanical.
  • The scripting compile is a model, not a toolchain. Visual logic and TS lower to a shared canonical IR; the real sandboxed WASM is the Wasmtime runtime on the Ixchel page, not a binary produced here.
  • No DCC import exists. FBX/glTF/USD/Alembic import, photogrammetry/splat ingest, and Nanite/LOD auto-optimization are spec, not code; the in-realm builder is the committed geometry path.
  • The web Studio is two route shells. accessibility/ and localization/ render real evals; the full builder/browser web UI is product surface.

Where this connects#