# Betworld Creator Documentation # Build with your AI Source: https://docs.betworld.gg/agent-guide/ ## Give your assistant a starting point Connect your world's MCP credential using [Connect your AI](/connect-mcp/), then give your assistant your design brief and this documentation URL. Connect local Blender MCP and install the [Betworld bridge](/blender/) to model and transfer assets. Start with `world_download`. Its response includes your world ID, revision, document, asset library, catalog and limits. Use these values for subsequent edits. ## Build and save in small steps 1. Download the current draft and record its revision. 2. Choose supported game stations and lay out their player approaches at the standard height and scale. 3. Model props in Blender and export static, self-contained GLBs with embedded textures. 4. Upload a representative prop with `asset_upload`. Save its returned hash and size. 5. Place it using `world_edit_entities`. Each `upsert` or `remove` array accepts up to 1,000 entries. Use the returned revision for the next edit. 6. For a complete layout replacement, call `world_upload` with the current revision and complete document, including any skin definitions you want to retain. 7. Check the returned budget after each meaningful change. Adjust geometry, textures or placements before reaching a limit. 8. Download again to confirm the saved placements and asset references. 9. Open your world panel or in-game builder and publish the saved revision. New bets pause while accepted wagers finish, then connected players automatically load the new layout. For direct integrations, the [World HTTP API](/world-api/) documents equivalent REST requests, authentication, responses and errors. ## Create custom game bodies and buttons Read [the Blender authoring workflow](/model-authoring-workflow/) and the [guide for each game](/betting-models/). Fetch `game_skin_contract` for the exact sockets and catalog fingerprint. Import the native game as a locked reference. Preserve its player/table ratio, screens, card paths and button positions. Export your replacement body and button artwork as separate GLBs. Upload them, replace the starter manifest's placeholder hashes, then use `game_skin_save` with the target entity IDs and current revision. Each binding maps one catalog slot to one uploaded asset hash. Betworld supplies the action and live state for that slot. Omitted bindings keep their native appearance. Use separate prop entities for surrounding scenery. Preview the states that affect clearance: Blackjack splits, all Multiplayer Blackjack seats, Baccarat third cards, Poker Holds, Mines grid sizes, Drago difficulties, Keno paytables, Dice slider extremes, Plinko outer pockets and Coinflip's full toss. Use local preview fixtures to inspect active states. When revising artwork, upload it again and use the returned hash. Replace the old placement or binding to avoid doubled geometry. Existing asset-library entries continue to count toward your storage limit. ## Handle revision conflicts A `409` means your saved revision is stale or the world cannot currently be published. Download the latest draft, merge your intended change and retry with its current revision. Keep edits sequential so one save's returned revision becomes the next save's input. A `401` on token routes means you need the current credential. Tokens stay valid until you revoke or replace them. Store them in your AI client's secret settings. ## Review your saved world Ask your assistant to report the world name and ID, saved revision, placed-entity count, download size, estimated memory, custom assets and any remaining layout issues. Preview the player approaches and controls, then publish from your world panel. ## Machine-readable references - [world.schema.json](/world.schema.json): accepted world structure; see [world format](/world-format/) for semantic rules. - [limits.json](/limits.json): current numerical budgets. - [catalog.json](/catalog.json): built-in props, games and station counts. - [game-skin-catalog.json](/game-skin-catalog.json): reference bounds, named controls, presentation targets and motion channels. - [game-model-reference.json](/game-model-reference.json): measured native meshes, physical controls, library hashes and runtime mounts. - [model-proportions.json](/model-proportions.json): player/table ratios and source scales. - [betting-interfaces.json](/betting-interfaces.json): generated screen regions and runtime anchors. - [llms-full.txt](/llms-full.txt): all guides as plain text. --- # Custom assets Source: https://docs.betworld.gg/assets/ ## Accepted format Upload a **static, self-contained GLB 2.0**. Textures and binary buffers must be embedded. External URLs, external buffers and unsupported extensions are rejected. Uploaded content must contain triangle meshes and valid references. Accepted image sources are static PNG, JPEG or WebP; the converter fully decodes and re-encodes them. Maximum dimension is 2048 pixels per side, with a total decoded pixel budget of 4,194,304 per prop. Animated images, rigs, skinning, morph targets and prop animation are not supported. Never upload `.blend`, `.py`, JavaScript, HTML, shaders, executables or archives as world assets. A GLB extension does not bypass validation; malformed files are rejected by structure and content. ## Size limits - At most **4 MB decimal** per input GLB and converted output. - At most **100 MB** in the creator's entire uploaded model and background library, shared across their worlds. - At most **512 files** across models and panoramas. Prop uploads allow **60 attempts per rolling hour**, and panoramas allow **12**. Failed conversions count, and MCP and browser uploads share the same allowance. - At most **100 MB total download** for one world: its manifest, standard source assets and distinct uploaded assets. Repeating one model adds entity data but does not download the model again. - A separate **500 MB estimated memory** limit accounts for decoded geometry, textures, instances and collision data. An asset can be small on disk but expensive in memory. Compressed textures expand when decoded. Every placed copy contributes to instance and collision memory and the placed-triangle budget, even though shared geometry downloads once. ## Upload and use your asset Use `asset_upload` through MCP, or send raw GLB bytes to `POST /api/worlds/ai/assets/upload` with your world token. The response includes the converted asset's `hash`, `size`, `triangles`, `pixels` and `meshes`. Both upload methods send file contents directly to Cloudflare. Disposable offline converters sanitize and validate the file before storing the canonical result in R2. Betworld's application server authorizes your account or world token and records the validated hash and geometry budget; it does not receive the uploaded model bytes. Downloads come directly from R2 through the existing Betworld URLs. Use `asset: "upload:"` in a prop entity, or the bare hash in a game-skin manifest. Download the returned asset URL to inspect the converted result. See the [HTTP API](/world-api/) for headers, examples and errors. ## Practical modeling advice Use a modest number of materials and mesh parts. Reuse shared props rather than uploading the same shape with slight color changes; entity tint can handle those. Merge fine details into one sensible mesh. Avoid giant textures for small objects. Bake complex appearance into textures rather than runtime shaders or scripts. The official bridge centers custom models horizontally, places their bottom at zero and normalizes their maximum extent. ## Asset lifecycle Uploading adds a library asset; saving a world references it; publishing makes that layout available to players. Assets use immutable URLs. There is currently no public library-delete tool, so avoid uploading unused variants to conserve the 100 MB library allowance. Requesting an existing owner-scoped canonical asset does not add duplicate stored bytes. ## Game skin assets Replacement bodies, button shapes and playing surfaces use this same static GLB upload pipeline. Upload each distinct piece separately, then use its returned canonical hash in a [skin manifest](/game-skin-contract/). Do not create a separate prop entity for a bound button. The runtime fits the piece to its reference socket, then applies v2 transforms to the visual and native interaction proxy; uploaded names/extras cannot choose an action. Every used hash counts toward world download/texture budgets, and every placed body/binding counts toward geometry and estimated memory budgets. ## Background images Upload panoramas separately from GLB props using **World → Upload panorama**, `background_upload` through MCP, or `POST /api/worlds/ai/backgrounds/upload`. Images use the same 100 MB library quota and have their own format and dimension limits. See [terrain and backgrounds](/terrain-backgrounds/) for the full reference. --- # Custom avatars and Unity packages Source: https://docs.betworld.gg/avatar-imports/ ## Uploading a character Open **Character & effects → Your own avatar → Upload model** while signed in to a registered account. Choose a `.glb`, `.vrm` or `.unitypackage` file. A valid conversion becomes your custom avatar. A rejected upload keeps your previous avatar and selection unchanged. Your upload is converted into a self-contained GLB that other players download. For Unity packages, include one assembled character model and its supported textures. Upload characters and textures you have permission to distribute. ## Exact upload and rendering limits | Limit | Value | | --- | --- | | Original upload | **30,000,000 bytes**, inclusive: decimal 30 MB | | Attempts | **6 per registered player in a rolling 60-minute window** | | Failed conversions | Consume an attempt once admitted | | Shared quota | GLB, VRM and Unity package uploads share the same six attempts | | Converted downloadable avatar | **4,194,304 bytes**, inclusive: 4 MiB | | Expanded Unity archive | Smaller of 120,000,000 bytes and `max(8,000,000, compressedBytes × 200)` | | Archive decompression time | 5 seconds | | Archive entries / Unity assets | 4,096 / 1,024 | | Models inside one package | One binary FBX, GLB or VRM, or one supported assembled text-mesh prefab | | Meshes / material primitives | 48 / 96 | | Mesh vertices / triangles | 150,000 / **70,000** | | Vertices / triangles across placed mesh instances | 200,000 / **70,000** | | Draw calls across placed mesh instances | 256 | | Scenes | 4 | | Scene nodes / hierarchy depth | 256 / 32 | | Materials / textures | 32 / 16 | | Skins / total bone references | 4 / 256; FBX requires one armature | | Bone influences | At most four per vertex | | Morph targets | 32 per primitive | | Final texture size | At most 2,048 × 2,048 per texture | | Final aggregate decoded textures | 4,194,304 pixels | The 70,000-triangle limit is a hard rejection threshold. It counts repeated mesh instances and inactive objects, and is checked again before browser loading. Texture resizing never reduces or bypasses this triangle count. The file-size, format and HTTP-encoding preflight may reject a request before charging an attempt. Once admitted, malformed files, failed conversions, interrupted uploads and unavailable conversion capacity can consume it. Successful uploads also consume it. The API returns HTTP `429` with an ISO `retryAt` timestamp when the rolling allowance is exhausted. Uploading another format or making concurrent requests does not reset the counter. Registered players have a separate allowance of **one profile-picture attempt per rolling hour**, including failed conversions. Keep your final character within 4 MiB using modest geometry and compact texture atlases. Direct GLB/VRM source textures may total up to 64 megapixels, with at most 4,096 × 4,096 per image; the converter resizes and rewrites them to the final budgets. Duplicate images and unused emission maps are removed; eligible small color textures can share an atlas. Tiled or unsupported texture setups must fit the limits themselves. Strip unrelated assets before exporting a package to reduce its download and expansion size. If a package exceeds the expansion budget, export just the character and its textures, or upload a self-contained GLB/VRM. ## What a Unity package can contain Use an ordinary gzip-compressed Unity archive with GUID directories and `pathname`, `asset`, `asset.meta` and optional `preview.png` entries. Asset paths must be normal `Assets/...` paths. Links, traversal paths, duplicate entries, extended tar headers and nested archives are rejected. Files are never extracted using their supplied pathnames. For **binary FBX** packages: 1. Include one assembled character mesh/armature model, not multiple outfit or accessory FBX files. 2. Include its static PNG, JPEG or WebP textures as separate package assets. Embedded FBX images and external filesystem paths are not loaded. 3. Use unique texture basenames and unique material names. The converter can match an FBX texture reference to a package texture by basename, or a supported Unity material to a texture by its GUID. 4. Keep source textures within **16,777,216 pixels in total**. They are fully decoded, reduced proportionally to the final pixel/dimension budget, and rewritten as PNG before Blender receives them. Animated images are rejected. 5. Text Unity `.mat` files may supply their material name, `_MainTex` / `_BaseMap` texture GUID and `_Color` / `_BaseColor` RGBA values. For binary `.mat` files, the converter uses a unique local texture GUID hint, the FBX's supported material data or a uniquely named package texture. Name the texture after the material: `Body.mat` matches `Body.png` or an older FBX export such as `Body_00_00_00.jpg`. Ambiguous matches are rejected. Binary material objects are never instantiated; shader settings are discarded. Untextured materials retain a plain color. 6. Materials are rebuilt using the platform's standard rendering. Custom shader source, shader graphs, shader plugins, normal-map setups, transparency tricks and other Unity material features are not imported by this FBX path. For a packaged **GLB or VRM**, the model must already contain its images and binary data. Loose package textures do not fill missing external GLB references. The same strict GLB validation and final budgets apply as for a direct upload. Assembled Unity prefabs backed by text `Mesh` `.asset` files are also supported. The converter reads only a fixed set of transforms, skin geometry, bone weights, bind poses and material references. Packages containing multiple standalone FBX/GLB models still require an assembled export. Package scripts, plugins, shaders, scenes, controllers and SDK components are ignored; no Unity editor setup code is run. Export the assembled character with its intended clothing, dimensions and rig already applied. If your package requires an editor setup step, ask its author for an assembled GLB/VRM export. ## Humanoid preparation in Blender Use your trusted Blender installation and your own scene. Keep the character upright, with its feet near the floor and a consistent scale. Blender uses Z-up; its glTF exporter converts to Y-up. The runtime fits the character to Betworld's standard body height. Extremely flat, enormous, zero-height or malformed skeleton/mesh bounds are rejected. The skinned mesh must belong to the active scene and have one unambiguous set of these required humanoid bones: | Body part | Canonical node name | | --- | --- | | Hips | `casino_pelvis` | | Spine | `casino_spine1` | | Head | `casino_head` | | Upper arms | `casino_upperarml`, `casino_upperarmr` | | Forearms | `casino_forearml`, `casino_forearmr` | | Hands | `casino_handl`, `casino_handr` | | Thighs | `casino_thighl`, `casino_thighr` | | Calves | `casino_calfl`, `casino_calfr` | | Feet | `casino_footl`, `casino_footr` | Standard VRM humanoid metadata, common Mixamo bone names and common humanoid aliases are normalized to this vocabulary. This includes older FBX names such as `L_UpperArm`, `R_Forearm`, `L_Thigh`, `Head1` and `Neck1`. A `Spine → Spine1 → Spine2` chain maps its lower and middle joints to the spine and chest controls. Optional named chest, neck, toe and eye nodes can survive. Duplicate required bone mappings or missing required bones fail validation. Weight the mesh to its rig; merely naming unconnected objects is insufficient. Do not use more than four bone influences per vertex. Bounded sparse accessors in source VRMs are expanded into dense data with range, index and allocation checks. Unsupported compressed geometry extensions are rejected. Compatible skin tables and unused vertices are compacted; duplicate joint influences from older exporters are merged and normalized before strict output validation. VRM mouth and blink presets are retained; unused authoring expressions and imported animation clips are removed. VRM 0.x models are turned to match the game's forward direction; VRM 1.0 models already use it. Models that depend on VRM bone constraints are rejected with an export instruction. Bake those constraints into an ordinary humanoid rig before uploading; the importer does not run their limb drivers. Betworld drives movement and emotes through the humanoid rig. Preview walking, arm raises, crouching and emotes; adjust shoulder weights and joint placement in your source model where needed. Uploaded animation clips and Unity animator setup are omitted. Walking, running, jumping, crouching, swinging, sitting and the emote catalogue use Betworld's animations. The result depends on your avatar's joint placement and skin weights. Extra finger joints retain their imported pose unless they have a supported animation mapping; VRChat gesture controllers are not transferred. Mouth movement while speaking requires a recognized mouth shape such as `vrc.v_aa`, `jawOpen` or `mouthOpen`. A model without those shapes still supports body movement, but its mouth remains static. Recognized facial names such as `vrc.v_aa`, `vrc.v_oh`, `vrc.v_sil`, `vrc.blink_left` and `vrc.blink_right` can survive conversion. Facial deformation must stay within the character bounds. Export your character without hats, helmets or other headwear. ## After you upload Clients display up to 12 custom-avatar instances using four distinct models on desktop, or six instances using two distinct models with touch controls. Additional custom avatars use the default character so a crowded room does not keep loading more texture sets. This limit is separate from your avatar's individual file and geometry budgets. The upload panel shows transfer progress, elapsed conversion time and a cancel button. Requests have bounded deadlines, so a stalled request returns an error. The importer checks the archive, converts supported model and texture data, then validates the resulting humanoid GLB in a second fresh sandbox. Only a successful result replaces your current custom avatar. Failed conversions discard their temporary files and preserve your previous avatar and selection. Files upload directly through Cloudflare, which runs the converter and validator in separate disposable VMs. Temporary inputs and validated models use private R2 storage; only validated output is downloadable. The game server handles account authorization and model references, without receiving avatar file bytes. Large or unsupported avatars can still be rejected by the limits above. Read the returned error before retrying. An admitted retry uses another upload attempt. For geometry or rig errors, correct the source model; for unsupported package setup, use an assembled GLB/VRM export. ## HTTP reference for integrations Avatar upload uses the player's normal authenticated website session. **World MCP credentials do not authorize avatar uploads.** World prop/game-skin uploads remain static GLB workflows with their own limits; they do not accept Unity packages. `POST https://betworld.gg/api/avatars/upload` - Body: the original file bytes, not JSON, base64 or multipart form data. - `Content-Type: application/vnd.unity` for `.unitypackage`. - `Content-Type: model/gltf-binary` for `.glb` and `.vrm`. - No HTTP `Content-Encoding`; a Unity package's own bounded gzip archive is decoded inside the sandbox. - Existing authentication, same-origin and registration checks apply. - Success: JSON containing `player`, final byte `size` and, for Unity packages, a compatibility `notice`. - Errors include `401` unauthenticated, `403` registration/origin restriction, `413` oversized, `415` unsupported type/encoding, `422` invalid conversion, `429` quota exceeded and `503` converter unavailable. `GET /api/avatars/` returns the current `model`, `maxBytes: 30000000`, `outputMaxBytes: 4194304` and `uploadsPerHour: 6`. Do not automatically retry failed imports: each admitted retry can consume another attempt. Show the returned reason and help the creator correct their original asset. Prefer a direct self-contained GLB/VRM when the Unity package depends on unsupported setup. --- # Custom models for every game Source: https://docs.betworld.gg/betting-models/ [Read as Markdown](/raw/betting-models.md) · [Skin contract v2](/game-skin-contract/) · [Socket catalog](/game-skin-catalog.json) ## Supported customization Create a new cabinet, table body, pedestal or display frame in Blender. Upload static GLB assets, then bind the body and any custom button shapes to a real game entity using the versioned skin manifest. Betworld supplies live values, trusted actions and game rules; v2 JSON controls presentation layout and motion. Custom meshes never contain executable callbacks. | Request | Support | |---|---| | Replace a native game's visible body | All thirteen games | | Restyle physical button geometry | Exact `control.*` sockets listed for that game | | Restyle a static playing surface | Games exposing `part.playing_surface` | | Reuse the same skin across several stations | Yes, within the same game and creator library | | Keep native buttons while changing the body | Yes; use `bindings: []` | | Move/rotate/scale controls, body and live display | V2 placements within the documented bounds | | Animate models and the complete display | V2 idle/result clips for all thirteen games | | Customize card, coin or Plinko motion | V2 result-motion channels | | Replace cards, result faces, dynamic grids or authoritative screen content | Platform-owned | | Add code, callbacks, custom shaders or remote URLs | Rejected / never executed | | Add more playable stations by duplicating a decorative mesh | No; place an allowed game entity | Read the [exact contract](/game-skin-contract/) before modeling. Its per-game fingerprint, accepted JSON fields, fitting math, limits and ownership checks are part of the API. The [native geometry reference](/game-model-reference.json) provides additional measurements; its internal GLB extras are not the upload format. ## All thirteen games | Asset ID | Detailed guide | Customizable interface | |---|---|---| | `blackjack` | [Blackjack](/game-model-blackjack/) | Deal/stake/hand-action meshes and playing surface | | `blackjack_group` | [Multiplayer Blackjack](/game-model-blackjack_group/) | Twelve seat-specific hand-action meshes and playing surface | | `baccarat` | [Baccarat](/game-model-baccarat/) | Player/Tie/Banker, Deal, stake, Settings and playing surface | | `videopoker` | [Video Poker](/game-model-videopoker/) | Deal/Draw, five Hold buttons, stake, Settings and Paytable | | `mines` | [Mines](/game-model-mines/) | Contextual Bet/Cash out and Settings | | `keno` | [Keno](/game-model-keno/) | Bet, Random, stake and Settings | | `dragontower` | [Drago Tower](/game-model-dragontower/) | Contextual Bet/Cash out and Settings | | `dice` | [Dice](/game-model-dice/) | Bet, Flip, stake, Settings controls and static top | | `limbo` | [Limbo](/game-model-limbo/) | Bet, stake, Target/Settings controls and static top | | `plinko` | [Plinko](/game-model-plinko/) | Drop and Settings | | `coinflip` | [Heads or Tails](/game-model-coinflip/) | Heads/Tails, Flip, stake, Settings and static top | | `roulette` | [Doubler](/game-model-roulette/) | Display body; live panel controls remain platform-rendered | | `crash` | [Crash](/game-model-crash/) | Display body; live Bet/Cash out and Settings remain platform-rendered | Each game page lists the exact accepted socket IDs, fixed action/seat/index mapping, world-space dimensions, preserved dynamic regions and states to inspect. Do not substitute roulette-wheel behavior for the `roulette` ID: this game is Betworld Doubler. ## Start with this AI brief ```text Read https://docs.betworld.gg/game-skin-contract/ and the detailed guide for [game]. Download my world with MCP and get game_skin_contract for that game. Import the exact native template into Blender as a locked reference. Create an original [theme] replacement body within its fixed dimensions. Preserve every functional opening, card/coin/ball path and player approach. Export the body and any custom button/surface shapes as separate static GLBs. Upload through asset_upload and use only returned canonical asset hashes. Bind only listed sockets using game_skin_save and the current draft revision. Add v2 placements, clips and supported result motions as numeric JSON. Keep scripts, custom labels, odds and action arguments out of the manifest. Download again, inspect geometry and report the saved revision and budgets. Publish only through my signed-in owner control after the preview is reviewed. ``` Use the [authoring workflow](/model-authoring-workflow/), [Blender bridge](/blender/) and [MCP tool reference](/mcp-tools/). Separate decorative props remain useful for surrounding architecture, signs, rugs and furniture, but are not needed merely to replace a machine body. --- # Build and transfer with Blender Source: https://docs.betworld.gg/blender/ ## Install the bridge Download [betworld_blender.py](/downloads/betworld_blender.py). In Blender 4.2 or newer, open Preferences → Add-ons → Install from Disk, choose the file and enable **Betworld Worlds**. Open the 3D View sidebar and choose **Betworld**. Create a world credential on Betworld and paste it into the sidebar. This credential is needed whether you click the bridge's buttons yourself or ask an AI connected to local Blender MCP to invoke them. ## Download world and assets **Download world + assets** fetches the draft, built-in props, game models and the owner's used custom assets. It creates a new Blender scene and preserves existing scenes. World entities are represented by anchors with the inert `betworld_entity` custom property. The shell is marked separately and is not exported as a placed entity. The bridge normalizes uploaded props to a unit maximum extent and puts their bottom at floor level. Their placement scale restores the intended size. Use the downloaded templates to assess table proportions. See [custom model authoring](/custom-models/) for cabinet recipes and the exact Baccarat/Blackjack height ratios. The [model gallery](/model-gallery/) includes individual previews and public native-template downloads for offline reference. For detailed work, follow [the complete modeling workflow](/model-authoring-workflow/) and the [individual game guides](/betting-models/). [The model reference guide](/model-reference/) includes a local Python example that draws temporary control-clearance boxes from the current native geometry. These guides are not exported as props. ## Edit through your AI Ask the assistant to move entity anchors, rotate them around the vertical axis, recolor them and duplicate appropriate props. Preserve the metadata needed for export. New entities need unique IDs and valid catalog asset names. Each entity has translation, vertical-axis rotation and XYZ scale. General pitch/roll, animated props, arbitrary mesh scripts and procedural runtime modifiers are not part of the world format. Apply Blender modeling operations to geometry before exporting a custom static prop. Set each game anchor to its supporting floor elevation (Y = 0–64) with scale `[1,1,1]`; never scale their meshes to defeat that rule. Use the actual server-provided game templates. All three multiplayer Blackjack seats belong to their multiplayer table. ## Upload a custom prop Select the mesh objects that form one static prop and use **Upload selected prop**. Export produces a self-contained GLB without animations, skins, extras, cameras or lights. The server validates and canonicalizes it in an isolated converter. A successful upload returns an asset hash. The bridge creates an entity anchor around the selected prop and records its normalized placement. Upload the world draft afterward to save the placement. Uploading an asset alone does not change the published world. The prop must be at most **4,000,000 bytes** after conversion. Embedded texture dimensions are at most 2048 × 2048; total decoded texture pixels per prop are at most 4,194,304. Lower texture resolution before export if needed. See [asset rules](/assets/). ## Upload the draft **Upload world draft** reads entity anchors and submits the full document with the scene's stored revision. Success updates the scene's revision. If the draft changed elsewhere, download the current draft and reconcile changes instead of overwriting blindly. The bridge supports the world manifest transport limit, but Blender itself can use considerably more RAM than the web renderer. A world containing many distinct Blender objects is expensive to edit. Prefer linked objects and reusable assets, and use MCP entity batches for large repetitive layouts when a full Blender scene is unnecessary. ## Coordinates | World JSON | Blender | |---|---| | X | X | | Y (up) | Z | | Z | −Y | | yaw in radians | rotation around Z | | scale `[sx,sy,sz]` | scale `(sx,sz,sy)` | Set the root `buildSize` to 56–384 metres to choose the placement width. World positions are limited to X/Z within ±half that width and Y between 0 and 64. Games can move onto upper floors with unit scale; their dimensions relative to that floor stay unchanged. The Blender bridge preserves `buildSize`, terrain and background settings when round-tripping the world. It also imports the modular building kit supplied in `sources.building`; native doorway openings and stair/ramp collision are assigned by asset identity when playing. Keep the entrance clear: an entity origin with `abs(x) < 3` and `z > buildSize / 2 - 6` is rejected. Prop dimensions can extend beyond their origin, so also visually check walkways and doors. ## Useful bridge operators A trusted local Blender MCP can call `bpy.ops.betworld.download_world()`, `bpy.ops.betworld.upload_prop()` and `bpy.ops.betworld.upload_world()` after the user has installed the bridge and entered a credential. These operations run locally in Blender. They are not world scripts and must never be embedded in an upload. ## Replacement game skins The current bridge includes **Upload selected skin mesh** and **Save skin JSON to selected stations**. Skin asset upload returns a bare canonical hash without creating a scenery entity. Put the strict manifest in a Text datablock named `betworld-skin.json`, select matching game anchor objects and save. Existing skin definitions round-trip when downloading/uploading worlds. Download again to preview changes in a new scene. Blender previews static geometry; the browser supplies live screens, cards and game states. See [the complete skin workflow](/game-skin-contract/) and [all game guides](/betting-models/). --- # Connect MCP Source: https://docs.betworld.gg/connect-mcp/ ## Endpoint ```text https://betworld.gg/api/worlds/ai/mcp ``` The server uses **Streamable HTTP**, with stateless requests. Use a client that supports remote HTTP MCP and custom Bearer headers. A client that only supports local stdio needs a compatible HTTP bridge. A client that requires OAuth-only remote connections cannot use this credential directly; Betworld does not currently provide MCP OAuth discovery or an OAuth consent flow. ## Configuration example This is a common JSON configuration shape; your client's setting names may differ: ```json { "mcpServers": { "betworld": { "url": "https://betworld.gg/api/worlds/ai/mcp", "headers": { "Authorization": "Bearer REPLACE_WITH_YOUR_WORLD_CREDENTIAL" } } } } ``` Generate the real configuration from **Create world → Create MCP credential**. Store the credential in client secret settings where available. Never commit it, include it in screenshots, embed it in models or put it in a public URL. ## Scope and lifetime Each credential is bound to one owner and one world. It permits downloading that draft, saving changes and uploading static props to the owner's library. `asset_download` only resolves assets in that owner's library. It cannot publish, access wallets, place bets, modify another owner's world or execute server code. It has no automatic expiry: it remains valid until you revoke or replace it. Generating a replacement or clicking **Revoke access** invalidates the old token. Blender stores the token in a transient WindowManager property with `SKIP_SAVE`; the world file does not contain it. ## Check the connection Use your client's standard initialization and tool discovery flow. `tools/list` should expose `world_download`, `world_upload`, `world_edit_entities`, `asset_upload` and `asset_download`. For an HTTP diagnostic, set `BETWORLD_TOKEN` privately in your shell and initialize: ```bash curl --fail-with-body https://betworld.gg/api/worlds/ai/mcp \ -H "Authorization: Bearer $BETWORLD_TOKEN" \ -H 'Content-Type: application/json' \ -H 'Accept: application/json, text/event-stream' \ --data '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"world-builder","version":"1.0"}}}' ``` Let the client honor the protocol version returned by initialization. The official Blender bridge also supports the installed server's newer protocol framing. Do not assume an arbitrary protocol version is accepted. A persistent GET event stream returns **405** because this server is stateless. This does not mean that POST tool calls are unavailable. The bridge can read completed JSON or SSE responses. ## Betworld MCP and Blender MCP These are two separate connections: 1. **Betworld MCP**, hosted remotely, reads and validates your world and assets. 2. **Blender MCP**, on your computer or trusted workstation, lets the AI operate Blender. Use the [official Betworld Blender bridge](/downloads/betworld_blender.py) to transfer scenes. Install it from disk in Blender's add-on preferences, then open the **Betworld** sidebar. A local Blender MCP can invoke its operators and manipulate the imported scene. The remote Betworld service does not execute Python sent by a model. Only expose a local Blender MCP to a trusted client. It can run code on the machine where Blender runs; keep it bound to localhost or behind authenticated private access. This is separate from the restrictions on uploaded world data. The credential-creation response returns `expiresIn: null`. Your token remains valid until you revoke it or generate a replacement. Paste it again when reopening Blender if needed; the bridge keeps it outside your saved scene. For REST requests and credential management, see the [World HTTP API](/world-api/). --- # Create custom models and preserve scale Source: https://docs.betworld.gg/custom-models/ For the full step-by-step process, use [the complete Blender and AI workflow](/model-authoring-workflow/). The [game-model guide index](/betting-models/) links detailed instructions for all 13 supported game types. Current physical control measurements are generated from the shipped GLBs in [game-model-reference.json](/game-model-reference.json); read [how to use that reference](/model-reference/) before applying transforms. ## What you can create Use an AI connected to your local Blender MCP to model signs, furniture, architecture, game bodies and physical buttons. Export static GLB geometry and materials, then connect game artwork through named skin slots. Betworld supplies live screens, cards, input handling and settlement. Create **replacement game bodies and custom physical-button meshes through [game skin contract v2](/game-skin-contract/)**. Use v2 placements to move controls and the display, and numeric clips/motions to animate them. Actions, seat identities and result values remain linked to Betworld. Uploaded GLB names/extras still do not bind actions: use the strict manifest and exact per-game socket catalog. Separate decorative props remain supported for scenery. Custom world props and custom player avatars are separate pipelines. The world prop uploader accepts static scenery, not humanoid rigs. The built-in player previews in the gallery are scale references; uploading one as a world prop does not make it an animated player. ## Start from the actual game reference 1. Create a world on Betworld and obtain its world credential. 2. Install the [Blender bridge](/blender/) and connect your AI to local Blender MCP. 3. Download the world and assets. The bridge places the native game templates at their correct scale. 4. Keep the game entity anchor and all native meshes as a locked reference. Build new artwork in a separate collection. 5. Place a player-height reference beside the station, on the same floor. Keep the native screen, controls, card paths and player approaches visible while modeling. 6. For a replacement skin, export body/button/surface assets separately and use `game_skin_save`. For surrounding scenery, upload separate props. Keep a real `kind: "game"` entity in either case. Downloading through the bridge is the preferred workflow because it applies the source-model scale for you. Do not multiply an already downloaded game by the source scale again. ## Preserve table height relative to the player Betworld's units are game units. Do not assume that one raw GLB unit is one real-world meter or change the table to match a real casino's dimensions. | Measurement | Source-model units | World units | |---|---:|---:| | Canonical bare player body | 1.818600 | 2.852274 | | Walking eye height | 1.683000 | 2.639600 | | Blackjack playing plane | 0.877903 | 1.376895 | | Baccarat playing plane | 0.877904 | 1.376895 | | Multiplayer Blackjack playing plane | 0.876207 | 1.374234 | The shared source-to-world scale is **1.5683897801544864**. Baccarat's playing plane is **48.2736079% of the canonical body height**. Blackjack uses almost the same ratio; Multiplayer Blackjack is **48.1803147%**. Preserve those relationships rather than estimating from a screenshot. The canonical body measurement excludes hair and hats. A clothed player preview can therefore be taller. The physics collision capsule is also a different measurement; do not use it as the visual body height when sizing furniture. The table rim can sit above the playing plane. Raising the cards to the rim would change their intended alignment. For an authoring reference with canonical body height `H`, Baccarat's playing plane should be `H * 0.48273607884945505`. For the actual Betworld game, retain the downloaded dimensions instead of rescaling anything. The world schema requires every game entity to have a supporting floor elevation Y = 0–64 and scale `[1, 1, 1]`. ### Source files versus world placement The [native game collection](/downloads/card-dice-tables.glb) uses source units. Imported directly into Blender, the canonical body reference is Z = 1.818600 and the Baccarat plane is Z = 0.877904. After applying the shared scale once, those become Z = 2.852274 and Z = 1.376895. Doubler and Crash come from the [prop and display collection](/downloads/creator-props.glb). They use their layout-specific scales, currently 1.05 and 0.63 respectively. Do not apply the card-table scale to them. The [machine-readable proportions](/model-proportions.json) distinguish these libraries. World JSON is Y-up; Blender is Z-up: world `[x, y, z]` maps to Blender `(x, -z, y)`. Keep the floor, model origin and vertical direction consistent. A negative scale or an unapplied axis conversion can mirror controls or move a decorative panel into the player approach. ## Optional Blackjack or Baccarat scenery Build side trim, a pedestal surround, separate supports or a nearby sign around the native table. Keep the original table top, monitors, card slots and buttons. Place the native template in a locked reference collection so the AI cannot accidentally export or resize it. For Baccarat, protect the Player, Banker and Tie betting regions, player and banker card slots, deck and stake monitor. For Blackjack, protect Hit, Stand, Double, Split, the dealer/player/split slots and the Bet/Settings monitor. Multiplayer Blackjack has three distinct seat interfaces attached to one table; do not create additional standalone game entities for those seats. Do not build a new solid table top over the functional one. It can cover the controls even if it looks correct in a still render. Do not bake cards, chip amounts, odds, results or active-button states into the artwork. The client owns those visuals. ## Design a custom Video Poker machine Use the native cabinet as a locked reference. Build a replacement body using the skin workflow, or add separate scenery panels and a marquee. Preserve these areas: | Region | Required behavior supplied by Betworld | |---|---| | Main screen | Paytable, five cards, status and results | | Five card targets | Hold/unhold the corresponding card index, 0–4 | | Deal / Draw | Start a hand or replace the unheld cards, depending on state | | Settings | Open the supported bet settings | | Paytable | Open the native settings/paytable interface | The screen is 3.82 × 2.865 world units, centered at `[0, 2.80, 0.51]` in station-local Y-up coordinates. Use the five card hit regions in [betting-interfaces.json](/betting-interfaces.json) and current physical button measurements in [game-model-reference.json](/game-model-reference.json). The older generated deck in the interface reference is a fallback hidden when the authored native controls are present. Do not use it to locate the current cabinet's buttons. The [Video Poker guide](/game-model-videopoker/) explains both coordinate spaces and the five physical Hold controls. The separate [betting-machine reference](/betting-models/) lists the required working areas for Mines, Keno, Drago Tower, Dice, Limbo, Plinko, Coinflip, Doubler and Crash as well. ## Model and export in Blender Create clean, low-complexity meshes. Prefer a few broad material regions, legible signage and small bevels. Use repeated assets as instances in the world rather than uploading many near-identical copies. Reusing one GLB saves download space, although each placed instance still consumes entity and memory budgets. Apply the modifiers needed to produce the final static geometry. Export a self-contained GLB with embedded textures. Do not include cameras, lights, skins, animation, external URLs or arbitrary metadata. A local Python script may create the mesh in Blender; that script stays on your machine and is never submitted as world content. Do not upload `.blend` files as props. For replacement skins use **Upload selected skin mesh** and the [skin contract](/game-skin-contract/). The remainder of this section describes separate scenery props. Select only the new decorative meshes and choose **Upload selected prop** in the Betworld bridge. The bridge exports, uploads, creates a prop anchor and restores the intended placement scale. Then upload the world draft to save that placement. Changing your local mesh after upload does not update the remote asset; upload the revised artwork and use the new returned asset reference. ### Scenery prop normalization and placement The renderer normalizes an uploaded prop so its longest bounding-box dimension is 1. Its bottom is placed at local Y = 0 and its horizontal bounding-box center is centered on the origin. A source prop whose longest dimension is 2.4 therefore needs a uniform entity scale of `[2.4, 2.4, 2.4]` to restore that size. The bridge handles this automatically. Position the prop's bottom-center anchor, not its geometric center. Preserve your intended aspect ratio with uniform scale. Stretching a single dimension can make a cabinet appear to fit while moving its edges across the functional screen. Uploaded scenery currently uses its oriented bounding box for collision. A single U-shaped surround produces a solid box that can block the player from reaching the table. Export left panel, right panel and other solid pieces separately. Avoid putting an overhead prop's collision box across a required walking route. There is no user-controlled script or collider override to make arbitrary scenery interactive or non-colliding. ## Budgets | Budget | Limit | |---|---:| | One uploaded prop after conversion | 4,000,000 bytes | | Owner's custom asset library | 100,000,000 bytes | | World downloads, including manifest and standard assets | 100,000,000 bytes | | Placed entities | 1,000,000 | | Estimated world memory | 500,000,000 bytes | | One embedded texture | 2048 × 2048 maximum | | Decoded pixels per prop | 4,194,304 | Check the returned budget after each asset or layout change. Every limit applies; see [limits and performance](/limits/) for download accounting and memory estimates. ## Wire your game artwork 1. Call `game_skin_contract` with the game's asset ID, such as `videopoker`. 2. Export and upload your body and button meshes with `asset_upload`. 3. Copy the contract's starter manifest, assign a unique skin `id` and replace the body hash with your uploaded hash. 4. Add bindings using the exact `slot` names from the catalog and your uploaded `asset` hashes. 5. Call `game_skin_save` with the manifest, target `entityIds` and current draft `revision`. 6. Use the returned revision for your next edit, and preview the station before publishing. The platform fits each mesh into its reference socket, applies v2 placements/clips, and supplies the socket's action. For example, each Video Poker Hold slot controls its assigned card, while Deal/Draw follows the current hand state. Omitted bindings retain their native appearance. See [game skin contract](/game-skin-contract/) for the complete manifest and [MCP tools](/mcp-tools/) for request and response examples. ## Copyable AI brief > Read https://docs.betworld.gg/llms.txt, /custom-models/, /betting-models/, /model-proportions.json and /betting-interfaces.json. Connect to my Betworld world through MCP and download it into Blender. Design an original ivory-and-teal Baccarat surround using separate static props around the native game. Keep the native table, floor height, scale, Player/Banker/Tie areas, card slots and monitor unchanged. Use the canonical body reference and preserve the 0.48273607884945505 playing-plane/body-height ratio. Leave every interaction and player approach clear. For full replacement bodies, switch to the documented game-skin contract and named sockets. Never upload scripts. Export only the decorative pieces, upload them through the bridge, save a draft and report the asset sizes, placement scale and remaining world budgets. For Video Poker, substitute its live screen, five card hit targets and current native physical-control measurements. Use the skin contract to replace the body and named physical buttons. Use v2 placements to move controls or the complete display. Video Poker supports display clips; its card ranks and Hold identities come from the live hand. --- # Baccarat model guide Source: https://docs.betworld.gg/game-model-baccarat/ [Read as Markdown](/raw/game-model-baccarat.md) · [All game guides](/betting-models/) · [Measured native reference](/game-model-reference.json) ## Replacement skin support This game supports the [v2 skin contract](/game-skin-contract/). Replace the visible body and the exact named physical meshes listed at the end of this page. Use the surround and trim suggestions below to add matching scenery. Preserve the functional regions and state-dependent clearances described here. ## Native identity and proportions Use `asset: "baccarat"`, IDs `baccarat:0` through `baccarat:8`, floor elevation Y = 0–64 and scale `[1,1,1]`. The root is `baccarat` in the game collection. Position and yaw can change; the table's functional dimensions cannot. The playing surface is 0.8779038617 source units and approximately 1.376895 world units high. Relative to the canonical bare player body, the ratio is **0.48273607884945505**. If making an offline scale sketch with body height `H`, place the playing plane at `H * 0.48273607884945505`. In the downloaded world, keep the actual native dimensions. Do not rescale the table to match real-world casino measurements or the rim in a concept image. ## Required controls and live areas | Region | Native function | Leave clear | |---|---|---| | Player | Selects Player | Its physical choice button and betting area | | Tie | Selects Tie | The middle choice and its label | | Banker | Selects Banker | Its physical choice button and betting area | | Deal | Starts the configured wager | The action button on the player side | | Stake − / + | Changes the configured stake when allowed | Both separate button faces | | Settings / stake monitor | Opens controls and shows the current amount | The visible screen and click surface | | Player and Banker card lanes | Dealing, optional third cards and totals | Full hand width and the travel from the deck | The native choice indices are **0 = Player, 1 = Tie, 2 = Banker**. They are described so an AI understands the template; the skin contract maps `control.choice_0`, `control.choice_1` and `control.choice_2` to those choices without accepting an uploaded index or action parameter. Runtime anchor names include `player_slot`, `banker_slot`, `player_chip_slot`, `tie_chip_slot`, `banker_chip_slot`, `deck` and `screen`. Read their transforms from the reference instead of placing cards by eye. ## Original decorative designs that fit Add a separate pedestal skirt in solid pieces, side medallions outside the native footprint, or a title sign behind the functional area. Use the game's supported felt tint for a coordinated palette. Keep the native top, choice controls and rail in place. Do not place another felt surface on top: it can hide live cards or intersect their animation plane. Use matte materials on broad surfaces so the native choice labels remain easy to read. Preserve the distinction between the three wager choices. Decorative symbols should not imply additional bets, changed payouts or an interactive fourth choice. Live amounts, odds, selection highlights and results remain client-rendered. ## Layout and state review Leave an unobstructed player approach on the front side. Align the walkway with the station's yaw and transform all decorative props with it. A rail or urn between the camera and the table can prevent interaction even if the player can reach the floor position. Review idle choice selection, dealing, two-card and three-card layouts, and the result state in an authorized preview or session. Check both Player and Banker lanes from portrait and landscape views. Do not add Hit, Stand or Cashout controls: Baccarat's dealing decisions are handled by the game, not by custom user buttons. ## AI brief ```text Get game_skin_contract for baccarat and download my current world draft. Build an original [theme] replacement body in Blender using the reference socket measurements and the preserved gameplay regions described in this guide. Upload static body/button assets; bind only the listed control/part sockets. Keep native labels, game values and collision. Use supported v2 placements, clips and result-motion channels for presentation changes. Save with game_skin_save and the current revision. Inspect the fitted model and report budgets and reviewed states. Do not upload code or publish via MCP. ``` See [modeling workflow](/model-authoring-workflow/) and [scale reference](/custom-models/) before export. ## Reference skin sockets (v1 and v2) Read `game_skin_contract({"game":"baccarat"})` before saving. The current fingerprint is `977206937f57deca`. The [live catalog](/game-skin-catalog.json) is authoritative if a copied example differs. The replacement body is fitted to station-local world bounds `[-2.9799405, 0, -2.2114296]` through `[2.9799405, 2.1514812, 2.1421068]`. Width, height and depth are `[5.9598811, 2.1514812, 4.3535364]`. These values already include source scale. Entity scale remains `[1,1,1]`. | Accepted binding slot | Fixed native action | Fixed index / seat | Native label | World-space bounds, minimum → maximum | |---|---|---|---|---| | `control.stake_up` | `stake_up` | None | + | `[-1.307622, 1.5770159, 1.4363936]` → `[-1.0449626, 1.6789612, 1.720139]` | | `control.choice_2` | `choice` | index 2 | BANKER | `[0.5617073, 1.5770159, 1.3563146]` → `[1.2576248, 1.6789612, 1.9332376]` | | `control.quick` | `quick` | None | DEAL | `[1.4435443, 1.5770159, 0.8670745]` → `[2.2578554, 1.6789612, 1.6505062]` | | `control.choice_0` | `choice` | index 0 | PLAYER | `[-0.9307255, 1.5770157, 1.431107]` → `[-0.2612508, 1.6789611, 1.9673178]` | | `control.settings` | `settings` | None | SETTINGS | `[2.448387, 1.5770159, 0.0489424]` → `[2.8527706, 1.6789612, 0.5784135]` | | `control.choice_1` | `choice` | index 1 | TIE | `[-0.1571137, 1.5770161, 1.4978473]` → `[0.4707916, 1.6789614, 1.9747576]` | | `control.stake_down` | `stake_down` | None | − | `[-1.6444073, 1.5770157, 1.3190743]` → `[-1.366901, 1.6789611, 1.6138176]` | Only `slot` and the converted model `asset` hash go in each binding. Action, index and seat columns explain platform behavior; **do not copy them into uploaded JSON**. All listed sockets are optional visual overrides. Omitted sockets retain native meshes. Repeated Settings actions are distinct physical sockets and must use the exact listed ID. The catalog provides exact mesh-local `localBounds` for fitting and the full `matrixSource` for native orientation. Optional static surface: `part.playing_surface`, native reference `top`, world bounds `[-2.5627488, 1.3580748, -1.6562196]` through `[2.5627488, 1.3768955, 1.6562196]`. Its replacement does not move cards, the animation rig or the interaction proxy. Save a skin with `game: "baccarat"`, its current fingerprint, a converted `body` hash and the chosen `bindings`. Apply it only to existing `baccarat:` entities. Declare each binding in the skin manifest. Follow [the exact manifest and fitting rules](/game-skin-contract/) and [the export workflow](/model-authoring-workflow/). ## V2 layout and animation Fetch `game_skin_contract({"game":"baccarat"})`. Use `presentation.targets` to position the body, complete display and each listed physical control. Control labels and clickable proxies follow their target; action/index/seat identity stays the same. Numeric `idle` and `result` clips are supported. Its result-motion channels are `card_deal`. Use the per-result progress and zero endpoint offsets described in the contract. Reference dimensions above describe the neutral layout before v2 placement. See the [exact fields, transforms and limits](/game-skin-contract/). --- # Blackjack model guide Source: https://docs.betworld.gg/game-model-blackjack/ [Read as Markdown](/raw/game-model-blackjack.md) · [All game guides](/betting-models/) · [Measured native reference](/game-model-reference.json) ## Replacement skin support This game supports the [v2 skin contract](/game-skin-contract/). Replace the visible body and the exact named physical meshes listed at the end of this page. Use the surround and trim suggestions below to add matching scenery. Preserve the functional regions and state-dependent clearances described here. ## Station and scale Use `asset: "blackjack"` and an available ID from `blackjack:0` through `blackjack:10`. Place the game at floor elevation Y = 0–64, yaw as needed, scale `[1,1,1]`. The native root is `blackjack` in the game library. Read `games.blackjack` in the reference JSON for measured physical controls and bounds. The playing plane is approximately 1.376895 world units above the floor: 48.2736% of the canonical bare player body height. Preserve the plane, rather than raising it to the top of the padded rail. The bridge already applies native scale. See [proportions](/custom-models/) for exact values. ## Functional regions to retain | Region | Native behavior | Modeling constraint | |---|---|---| | Deal | Starts a hand with the configured stake | Keep its button face and front approach exposed | | Stake − / + | Adjust the next stake when allowed | Leave both visible; do not replace with a printed amount | | Hit / Stand | Player hand decisions | Preserve separate, readable button faces | | Double / Split | Conditional hand decisions | Disabled states are meaningful; do not repaint as permanently active | | Surrender | Available only in supported hand states | Retain the supplied control; do not create your own action | | Bet monitor / settings surface | Shows stake and opens supported controls | Keep its surface and surrounding sightline clear | | Dealer hand, player hand, split hands, deck | Card placement, dealing and totals | Reserve space above the felt and between every anchor | Native references include `dealer_slot`, `deck`, `hand_0_slot`, `hand_0_slot_split`, `hand_1_slot_split`, `btn_hit`, `btn_stand`, `btn_double` and `btn_split`. The current physical Deal, stake and Surrender controls are also listed in `controls`, even when they do not have a `referencePart` name. A runtime `screen` mount can exist without a visible named screen mesh; do not delete its space because you cannot see a monitor in an offline GLB viewer. These names explain the trusted model. Naming your uploaded mesh `btn_hit` does not wire it to Hit. ## Buildable artwork Make separate decorative side supports, a rear sign outside the dealer/card area, or trim on the exterior of the pedestal. Build the top and rail around your chosen v2 control/display layout. Keep the labels and full button faces exposed. Keep new trim away from both the button face and the player's ray to that face. Theme the surrounding floor with a walkway leading to the player side. Keep furniture out of the automatic viewing approach. A chair can obstruct that approach even if its rendered legs leave a visible gap: the prop collider is a box. Add another Blackjack entity for another playable station; a mirrored decorative table is only scenery. ## Card and control states to inspect An idle screenshot does not show the full needed space. Preserve the dealer reveal, additional cards after Hit, multiple split-hand lanes, totals and result text. Check the initial two-card hand and a wide card fan. During a hand, action availability follows server state; Double, Split and Surrender are not always available. In a finished hand, controls return to the next-hand state. Review from standing eye height, an oblique angle and a portrait phone. Native cards must remain above the felt and below your decoration without flicker. Do not bake a sample hand, chip amount or dealer result into the artwork. Betworld supplies those visuals and the game logic. ## AI brief ```text Get game_skin_contract for blackjack and download my current world draft. Build an original [theme] replacement body in Blender using the reference socket measurements and the preserved gameplay regions described in this guide. Upload static body/button assets; bind only the listed control/part sockets. Keep native labels, game values and collision. Use supported v2 placements, clips and result-motion channels for presentation changes. Save with game_skin_save and the current revision. Inspect the fitted model and report budgets and reviewed states. Do not upload code or publish via MCP. ``` Follow the [full export and upload workflow](/model-authoring-workflow/). Replacement bodies and named button meshes use [skin contract v2](/game-skin-contract/). Use v2 placements and numeric result-motion channels for layout and animation. ## Reference skin sockets (v1 and v2) Read `game_skin_contract({"game":"blackjack"})` before saving. The current fingerprint is `f2e33f7bb6871174`. The [live catalog](/game-skin-catalog.json) is authoritative if a copied example differs. The replacement body is fitted to station-local world bounds `[-2.9799405, 0, -2.2289955]` through `[2.9799405, 2.1514812, 2.1421068]`. Width, height and depth are `[5.9598811, 2.1514812, 4.3711023]`. These values already include source scale. Entity scale remains `[1,1,1]`. | Accepted binding slot | Fixed native action | Fixed index / seat | Native label | World-space bounds, minimum → maximum | |---|---|---|---|---| | `control.stake_up` | `stake_up` | None | + | `[-1.3397117, 1.5770159, 1.4266842]` → `[-1.0756085, 1.6789612, 1.7115332]` | | `control.quick` | `quick` | None | DEAL | `[1.6829154, 1.5770159, 0.7443842]` → `[2.4576338, 1.6789612, 1.5148185]` | | `control.double` | `double` | None | DOUBLE | `[0.3749485, 1.5770159, 1.4208771]` → `[0.9738668, 1.6789612, 1.9548746]` | | `control.hit` | `hit` | None | HIT | `[-0.9738668, 1.5770159, 1.4208771]` → `[-0.3749485, 1.6789612, 1.9548746]` | | `control.split` | `split` | None | SPLIT | `[1.0217327, 1.5770159, 1.2209995]` → `[1.6758978, 1.6789612, 1.8272897]` | | `control.stand` | `stand` | None | STAND | `[-0.2666263, 1.5770159, 1.5116142]` → `[0.2666263, 1.6789612, 1.9664472]` | | `control.surrender` | `surrender` | None | SURRENDER | `[2.448387, 1.5770159, 0.0489424]` → `[2.8527706, 1.6789612, 0.5784135]` | | `control.stake_down` | `stake_down` | None | − | `[-1.6604352, 1.5770159, 1.3125783]` → `[-1.3822411, 1.6789612, 1.607809]` | Only `slot` and the converted model `asset` hash go in each binding. Action, index and seat columns explain platform behavior; **do not copy them into uploaded JSON**. All listed sockets are optional visual overrides. Omitted sockets retain native meshes. Repeated Settings actions are distinct physical sockets and must use the exact listed ID. The catalog provides exact mesh-local `localBounds` for fitting and the full `matrixSource` for native orientation. Optional static surface: `part.playing_surface`, native reference `top`, world bounds `[-2.5627488, 1.3580739, -1.6562196]` through `[2.5627488, 1.3768946, 1.6562196]`. Its replacement does not move cards, the animation rig or the interaction proxy. Save a skin with `game: "blackjack"`, its current fingerprint, a converted `body` hash and the chosen `bindings`. Apply it only to existing `blackjack:` entities. Declare each binding in the skin manifest. Follow [the exact manifest and fitting rules](/game-skin-contract/) and [the export workflow](/model-authoring-workflow/). ## V2 layout and animation Fetch `game_skin_contract({"game":"blackjack"})`. Use `presentation.targets` to position the body, complete display and each listed physical control. Control labels and clickable proxies follow their target; action/index/seat identity stays the same. Numeric `idle` and `result` clips are supported. Its result-motion channels are `card_deal` and `card_flip`. Use the per-result progress and zero endpoint offsets described in the contract. Reference dimensions above describe the neutral layout before v2 placement. See the [exact fields, transforms and limits](/game-skin-contract/). --- # Multiplayer Blackjack model guide Source: https://docs.betworld.gg/game-model-blackjack_group/ [Read as Markdown](/raw/game-model-blackjack_group.md) · [All game guides](/betting-models/) · [Measured native reference](/game-model-reference.json) ## Replacement skin support This game supports the [v2 skin contract](/game-skin-contract/). Replace the visible body and the exact named physical meshes listed at the end of this page. Use the surround and trim suggestions below to add matching scenery. Preserve the functional regions and state-dependent clearances described here. ## One table, three seats Use `blackjack_group:0` or `blackjack_group:1`, with `asset: "blackjack_group"`, floor elevation Y = 0–64 and scale `[1,1,1]`. The client creates three seat interfaces and their station identities from that table. Do not add the internal shared-seat Blackjack IDs as independent world entities. Do not upload three separate decorative tables and expect them to share a round. The native root is `blackjack_group` in the game library. Its playing plane is approximately 1.374234 world units, or 48.1803% of the canonical body height. Keep the downloaded scale and use the runtime table transform for all seats. ## Protect each seat separately | Region | Requirement | |---|---| | `seat_0_screen` … `seat_2_screen` | Preserve all three native monitor mounts and Bet/Settings interfaces | | Seat Hit / Stand / Double / Split controls | Each seat has its own controls; do not merge their artwork or overlap adjacent button banks | | `player_slot_0` … `player_slot_2` | Keep each main hand lane clear | | `player_slot__split_0` and `_split_1` | Keep each seat's split-hand area clear | | `bet_slot_0` … `bet_slot_2` | Preserve betting/chip reference space | | `dealer_slot`, `deck` | Keep the common dealer and dealing route visible from all seats | | `wagers_screen` | Leave the shared status area readable | The generated `controls` array includes a `seat` value of 0, 1 or 2. This is a measurement of native controls, not a creator setting for assigning a custom prop to a seat. Screen and card mounts are in `runtimeMounts`; some are non-rendered anchors. ## Theme the table without partitioning it Use low exterior side trim, pedestal accents or a separate sign behind the common dealer area. Keep the existing top and all three control banks. Avoid tall separators between seats: another player's view and card lane can cross that divider. An opaque sign that looks good from seat 1 can hide the dealer from seat 0 or 2. Plan three approach corridors around the native table, plus a route behind players. Keep the seat viewing positions free of planters, chairs, posts and rugs with excessive thickness. Do not infer shared-seat positions from an equally spaced semicircle in an image; use the downloaded template. Rotating the table rotates the whole three-seat arrangement. Rotate its decorative props as the same assembly. ## Round states and animation The display distinguishes betting, playing, waiting for a turn and settlement. A seat cannot always act just because another player's controls are active. Preserve the native state cues and labels. Keep all dealer travel and all player card fans unobstructed, including split hands at the outer seats. For visual review, look from all three seat positions, not only from the center. Also view the table while walking past it. Check that each screen remains separate and that the same button cannot appear to belong to two seats. Real state validation belongs to Betworld; creator artwork does not implement a turn timer or deal sequence. ## AI brief ```text Get game_skin_contract for blackjack_group and download my current world draft. Build an original [theme] replacement body in Blender using the reference socket measurements and the preserved gameplay regions described in this guide. Upload static body/button assets; bind only the listed control/part sockets. Keep native labels, game values and collision. Use supported v2 placements, clips and result-motion channels for presentation changes. Save with game_skin_save and the current revision. Inspect the fitted model and report budgets and reviewed states. Do not upload code or publish via MCP. ``` Use [the common workflow](/model-authoring-workflow/) for normalization, upload and publication. The skin pipeline replaces the visible table body and approved seat-action meshes; the shared game logic and live seat panels remain platform-owned. ## Reference skin sockets (v1 and v2) Read `game_skin_contract({"game":"blackjack_group"})` before saving. The current fingerprint is `9530715fe0bb2934`. The [live catalog](/game-skin-catalog.json) is authoritative if a copied example differs. The replacement body is fitted to station-local world bounds `[-3.8582389, 0, -0.9880856]` through `[3.8582389, 3.7170839, 4.228379]`. Width, height and depth are `[7.7164778, 3.7170839, 5.2164646]`. These values already include source scale. Entity scale remains `[1,1,1]`. | Accepted binding slot | Fixed native action | Fixed index / seat | Native label | World-space bounds, minimum → maximum | |---|---|---|---|---| | `control.seat_0_double` | `double` | seat 0 | DOUBLE | `[2.503123, 1.5770159, 2.3243863]` → `[2.9180209, 1.6789612, 2.7450909]` | | `control.seat_1_double` | `double` | seat 1 | DOUBLE | `[0.1236027, 1.5770157, 3.4840642]` → `[0.4546482, 1.6789611, 3.7858065]` | | `control.seat_2_double` | `double` | seat 2 | DOUBLE | `[-2.6094675, 1.5770159, 2.6520564]` → `[-2.1875911, 1.6789612, 3.0704851]` | | `control.seat_0_hit` | `hit` | seat 0 | HIT | `[1.7935623, 1.5770159, 2.9414472]` → `[2.206757, 1.6789612, 3.3433516]` | | `control.seat_1_hit` | `hit` | seat 1 | HIT | `[-1.0380837, 1.5770159, 3.392938]` → `[-0.675857, 1.6789612, 3.7304338]` | | `control.seat_2_hit` | `hit` | seat 2 | HIT | `[-3.1171901, 1.5770159, 1.9743272]` → `[-2.732924, 1.6789612, 2.3747825]` | | `control.seat_0_split` | `split` | seat 0 | SPLIT | `[2.732924, 1.5770159, 1.9743272]` → `[3.1171901, 1.6789612, 2.3747825]` | | `control.seat_1_split` | `split` | seat 1 | SPLIT | `[0.675857, 1.5770159, 3.392938]` → `[1.0380837, 1.6789612, 3.7304338]` | | `control.seat_2_split` | `split` | seat 2 | SPLIT | `[-2.206757, 1.5770159, 2.9414472]` → `[-1.7935623, 1.6789612, 3.3433516]` | | `control.seat_0_stand` | `stand` | seat 0 | STAND | `[2.1875911, 1.5770159, 2.6520564]` → `[2.6094675, 1.6789612, 3.0704851]` | | `control.seat_1_stand` | `stand` | seat 1 | STAND | `[-0.4546482, 1.5770157, 3.4840642]` → `[-0.1236027, 1.6789611, 3.7858065]` | | `control.seat_2_stand` | `stand` | seat 2 | STAND | `[-2.9180209, 1.5770159, 2.3243863]` → `[-2.503123, 1.6789612, 2.7450909]` | Only `slot` and the converted model `asset` hash go in each binding. Action, index and seat columns explain platform behavior; **do not copy them into uploaded JSON**. All listed sockets are optional visual overrides. Omitted sockets retain native meshes. Repeated Settings actions are distinct physical sockets and must use the exact listed ID. The catalog provides exact mesh-local `localBounds` for fitting and the full `matrixSource` for native orientation. Optional static surface: `part.playing_surface`, native reference `top`, world bounds `[-3.3180856, 1.3554138, -0.470517]` through `[3.3180856, 1.3742345, 3.670032]`. Its replacement does not move cards, the animation rig or the interaction proxy. Save a skin with `game: "blackjack_group"`, its current fingerprint, a converted `body` hash and the chosen `bindings`. Apply it only to existing `blackjack_group:` entities. Declare each binding in the skin manifest. Follow [the exact manifest and fitting rules](/game-skin-contract/) and [the export workflow](/model-authoring-workflow/). ## V2 layout and animation Fetch `game_skin_contract({"game":"blackjack_group"})`. Use `presentation.targets` to position the body, complete display and each listed physical control. Control labels and clickable proxies follow their target; action/index/seat identity stays the same. Numeric `idle` and `result` clips are supported. Its result-motion channels are `card_deal` and `card_flip`. Use the per-result progress and zero endpoint offsets described in the contract. Reference dimensions above describe the neutral layout before v2 placement. See the [exact fields, transforms and limits](/game-skin-contract/). --- # Heads or Tails model guide Source: https://docs.betworld.gg/game-model-coinflip/ [Read as Markdown](/raw/game-model-coinflip.md) · [All game guides](/betting-models/) · [Measured native reference](/game-model-reference.json) ## Replacement skin support This game supports the [v2 skin contract](/game-skin-contract/). Replace the visible body and the exact named physical meshes listed at the end of this page. Use the surround and trim suggestions below to add matching scenery. Preserve the functional regions and state-dependent clearances described here. ## Station identity The player-facing game may be called Heads or Tails or Coinflip. Its asset is **`coinflip`**, with station IDs `coinflip:0` through `coinflip:4`. Use floor elevation Y = 0–64 and scale `[1,1,1]`. The native root is `coinflip` in the game library. Preserve the supplied coin, pedestal and controls. A gold disc uploaded as a separate prop is static scenery; it will not inherit the native flip animation or become a wager target. ## Controls and readouts | Region | Native behavior | |---|---| | Heads | Selects Heads; native choice index 0 | | Tails | Selects Tails; native choice index 1 | | Flip | Starts the configured wager | | Stake − / + | Changes the configured stake when allowed | | SET / settings surface | Opens supported bet controls | | Coin surface | Also provides a native settings interaction | | `result_display` | Shows the selected side, flipping state and settled result | | `bet_display` | Shows the current stake | The current physical buttons are measured in `games.coinflip.controls`. The native `coin`, `top`, `result_display` and `bet_display` references identify the artwork and live-display locations. Use the current GLB and generated reference together; a generic round-table diagram does not describe its control placement. ## Animation clearance Leave space **above** the resting coin and around its full rotating shape. The rest-pose mesh bounds do not include its toss envelope. Do not add a low dome, hanging sign, foliage or decorative second coin in that volume. A still render can appear correct while the first animated flip clips through the new artwork. Both faces must remain visually distinct and visible during the native animation. Do not rotate, mirror, rescale or swap the actual coin mesh in a downloaded reference and expect the runtime to adopt it. Do not bake an always-visible Heads or Tails result into decorative artwork. The native client reconciles the final face and displayed outcome with the game result. ## Original surround recipe Use separate low pedestal accents, an outer side medallion or a small sign beyond the coin's travel. Keep the native top and its controls intact. Avoid an encircling shell whose box collider spans the player's approach. Keep front furniture low enough to reveal both the buttons and the result display from normal eye height. Use a neutral or coordinated material palette around the selection buttons so the native selection highlight stays obvious. A custom decorative heads/tails emblem should not look like a second clickable choice bank. Use the approved `control.choice_0` or `control.choice_1` skin socket for a functional replacement; body decoration alone has no action. ## Review and AI brief Inspect both selected sides, the start of the toss, the highest/rotating portion, landing on each face and the result readout. Confirm that the result and selected-side text are not confused. Check a portrait phone and a side view, not just a top-down render. Use an authorized preview for active animation; do not spend funds merely to check art. ```text Get game_skin_contract for coinflip and download my current world draft. Build an original [theme] replacement body in Blender using the reference socket measurements and the preserved gameplay regions described in this guide. Upload static body/button assets; bind only the listed control/part sockets. Keep native labels, game values and collision. Use supported v2 placements, clips and result-motion channels for presentation changes. Save with game_skin_save and the current revision. Inspect the fitted model and report budgets and reviewed states. Do not upload code or publish via MCP. ``` See [the shared authoring workflow](/model-authoring-workflow/) for export and alignment. ## Reference skin sockets (v1 and v2) Read `game_skin_contract({"game":"coinflip"})` before saving. The current fingerprint is `4aeda6f64c6196b1`. The [live catalog](/game-skin-catalog.json) is authoritative if a copied example differs. The replacement body is fitted to station-local world bounds `[-1.8820678, 0, -1.8820678]` through `[1.8820678, 2.2867124, 1.9651924]`. Width, height and depth are `[3.7641356, 2.2867124, 3.8472602]`. These values already include source scale. Entity scale remains `[1,1,1]`. | Accepted binding slot | Fixed native action | Fixed index / seat | Native label | World-space bounds, minimum → maximum | |---|---|---|---|---| | `control.stake_up` | `stake_up` | None | + | `[-1.1901888, 1.5770159, 1.0979373]` → `[-0.9114535, 1.6789612, 1.3851821]` | | `control.quick` | `quick` | None | FLIP | `[-0.893638, 1.577016, 1.1731573]` → `[-0.2983382, 1.6789613, 1.768457]` | | `control.choice_0` | `choice` | index 0 | HEADS | `[-0.1802341, 1.577016, 1.3181641]` → `[0.3057053, 1.6789613, 1.8041035]` | | `control.settings` | `settings` | None | SET | `[1.1092243, 1.5770159, 0.7276015]` → `[1.619774, 1.6789612, 1.2370141]` | | `control.choice_1` | `choice` | index 1 | TAILS | `[0.4431057, 1.577016, 1.1039054]` → `[1.0625484, 1.6789613, 1.7233481]` | | `control.stake_down` | `stake_down` | None | − | `[-1.4615017, 1.5770159, 0.8857512]` → `[-1.173393, 1.6789612, 1.1743036]` | Only `slot` and the converted model `asset` hash go in each binding. Action, index and seat columns explain platform behavior; **do not copy them into uploaded JSON**. All listed sockets are optional visual overrides. Omitted sockets retain native meshes. Repeated Settings actions are distinct physical sockets and must use the exact listed ID. The catalog provides exact mesh-local `localBounds` for fitting and the full `matrixSource` for native orientation. Optional static surface: `part.playing_surface`, native reference `top`, world bounds `[-1.6185782, 1.3927301, -1.5056542]` through `[1.6185782, 1.4115508, 1.5056542]`. Its replacement does not move cards, the animation rig or the interaction proxy. Save a skin with `game: "coinflip"`, its current fingerprint, a converted `body` hash and the chosen `bindings`. Apply it only to existing `coinflip:` entities. Declare each binding in the skin manifest. Follow [the exact manifest and fitting rules](/game-skin-contract/) and [the export workflow](/model-authoring-workflow/). ## V2 layout and animation Fetch `game_skin_contract({"game":"coinflip"})`. Use `presentation.targets` to position the body, complete display and each listed physical control. Control labels and clickable proxies follow their target; action/index/seat identity stays the same. Numeric `idle` and `result` clips are supported. Its result-motion channels are `coin_flip`. Use the per-result progress and zero endpoint offsets described in the contract. Reference dimensions above describe the neutral layout before v2 placement. See the [exact fields, transforms and limits](/game-skin-contract/). --- # Crash display model guide Source: https://docs.betworld.gg/game-model-crash/ [Read as Markdown](/raw/game-model-crash.md) · [All game guides](/betting-models/) · [Measured native reference](/game-model-reference.json) ## Replacement skin support This game supports the [v2 skin contract](/game-skin-contract/). Replace the visible body and the exact named physical meshes listed at the end of this page. Use the surround and trim suggestions below to add matching scenery. Preserve the functional regions and state-dependent clearances described here. ## Station and display scale Use `crash:0`, asset `crash`, floor elevation Y = 0–64 and scale `[1,1,1]`. One Crash station is permitted per creator world. Its native root comes from the **props/display library** and uses source-to-world scale **0.63**, not the card-table scale. The bridge already performs this conversion. The main live screen is 16 × 9 source units, centered at `[0,6,0.4]`, before the 0.63 scale and station position/yaw. Its canvas is 1920 × 1080, a 16:9 aspect ratio. A custom frame must preserve the whole rectangle, not crop it to a square or the central multiplier. ## Live regions that need clearance | Region | Behavior | |---|---| | Graph and moving arrow | Presents the shared round's progression | | Large multiplier / status | Shows the current round or connection state | | Participant list at the right | Shows recent participant bets/results and player interactions | | Bottom primary control | Bet, placed/waiting state or Cash out depending on round and player state | | Bottom settings area | Opens the supported bet configuration when shown | | Round countdown/status | Indicates betting availability and progress | The bottom control changes shape: Cash out can occupy the whole action area, while other states show a separate Settings region. Do not install a fixed decorative divider across that row. The graph and readouts are dynamic overlays slightly forward of the static face; preserve their depth as well as width and height. The native `controls` array can be empty in the geometry reference because Crash's interactions are generated screen regions. No custom mesh button is needed, and adding one does not wire it to Cashout. The creator cannot supply a different graph algorithm, timer or settlement function. ## Buildable custom artwork Use separate outside frame pieces, a low support accent and a title beyond the screen. Keep the original display model in place. A hollow frame exported as one prop still has a solid collision box; split it into solid pieces that do not block the viewing approach. Position a large display where players can stand back far enough to see the right-side list and bottom row. Avoid a bar or planter directly below it that hides the controls when viewed from a player's eye height. A wall recess needs enough depth to avoid clipping the native overlays. Do not place a second transparent panel in front of the screen. Use static artwork for theme and title only. Do not bake a multiplier, a “cashout available” badge, a player balance or a countdown into a texture. The native client can display reconnecting/unavailable states, and those messages must remain readable. A decorative green light must not falsely imply that a financial action succeeded. ## State review Inspect betting-open, bet-placed, running, cashout-available, already-settled, crashed and reconnecting presentations in an authorized preview. Only the appropriate player/round state can offer Cashout. The interface must remain legible when the primary row expands and when status text is longer than a number. Check portrait and landscape views and the player's route to Settings. This is an artwork review, not authorization to place a wager; use a preview environment or the owner's explicitly authorized session for active states. ## AI brief ```text Get game_skin_contract for crash and download my current world draft. Build an original [theme] replacement body in Blender using the reference socket measurements and the preserved gameplay regions described in this guide. Upload static body/button assets; bind only the listed control/part sockets. Keep native labels, game values and collision. Use supported v2 placements, clips and result-motion channels for presentation changes. Save with game_skin_save and the current revision. Inspect the fitted model and report budgets and reviewed states. Do not upload code or publish via MCP. ``` Read [the full modeling workflow](/model-authoring-workflow/) for export and transfer details. ## Reference skin sockets (v1 and v2) Read `game_skin_contract({"game":"crash"})` before saving. The current fingerprint is `cfc756e6e012b67b`. The [live catalog](/game-skin-catalog.json) is authoritative if a copied example differs. The replacement body is fitted to station-local world bounds `[-5.8907691, 0, -0.9218462]` through `[5.8907691, 8.7504733, 0.9304616]`. Width, height and depth are `[11.7815381, 8.7504733, 1.8523077]`. These values already include source scale. Entity scale remains `[1,1,1]`. There are **no physical-button replacement sockets** for this game. Use `bindings: []`. The platform generates all clickable screen regions, their labels and state-dependent availability. The body can be replaced; the interactive display supports v2 placement and clips, with live content supplied by Betworld. Save a skin with `game: "crash"`, its current fingerprint, a converted `body` hash and the chosen `bindings`. Apply it only to existing `crash:` entities. Declare each binding in the skin manifest. Follow [the exact manifest and fitting rules](/game-skin-contract/) and [the export workflow](/model-authoring-workflow/). ## V2 layout and animation Fetch `game_skin_contract({"game":"crash"})`. Use `presentation.targets` to position the body, complete display and each listed physical control. Control labels and clickable proxies follow their target; action/index/seat identity stays the same. Numeric `idle` and `result` clips are supported. Use a `result` clip on `display` to animate the live presentation; this game has no separate card/coin/ball motion channel. Reference dimensions above describe the neutral layout before v2 placement. See the [exact fields, transforms and limits](/game-skin-contract/). --- # Dice model guide Source: https://docs.betworld.gg/game-model-dice/ [Read as Markdown](/raw/game-model-dice.md) · [All game guides](/betting-models/) · [Measured native reference](/game-model-reference.json) ## Replacement skin support This game supports the [v2 skin contract](/game-skin-contract/). Replace the visible body and the exact named physical meshes listed at the end of this page. Use the surround and trim suggestions below to add matching scenery. Preserve the functional regions and state-dependent clearances described here. ## Station and native surface Use `dice:0` through `dice:4`, asset `dice`, floor elevation Y = 0–64, scale `[1,1,1]`. The root is `dice` in the game library. This game uses a low stepped control surface with a slider and display. It does not need a creator-authored rolling-dice physics simulation. Use `games.dice.controls` for the current button faces and `runtimeMounts` for the stepped sections and slider/display transforms. Older anchor names can describe reference locations rather than current visible buttons. Do not position new artwork from an old `roll_button` name alone; the generated control list measures the shipped native model. ## Functional regions | Region | Native behavior | |---|---| | Bet | Uses the configured stake and target | | Bet Size / Settings | Opens the supported bet controls | | Stake − / + | Changes the stake when allowed | | Flip | Switches the supported over/under direction | | Slider groove and target handle | Shows and changes the configured target | | Low/high fill sections | Indicate the target's two ranges | | Tick labels | Explain the numerical scale | | Main display | Shows target/result, chance, return information and status | | Result marker | Moves to the game result | The slider spans the native 0–100 reference scale; the current input clamps playable targets to 5…95 with half-unit selection steps. These values describe the interface, not permission to change the rules. Do not make a custom slider with new endpoints or an implied probability outside the native range. ## Protected transforms and movement Important runtime mounts include `section_2`, `section_3`, `slider_min`, `slider_max`, `screen` and the native slider references. The slider's live hit region is a 2.5 × 0.30 plane in its own transformed surface frame, not an axis-aligned plane at the game origin. Read the mount rotation as well as position. Keep the full handle travel clear, including both extremes. Low/high fills resize with the target and change visual meaning with Flip. The result marker travels across the same horizontal scale. A thin decorative strip over the groove may look harmless while still hiding the marker or intercepting the player's view. ## Artwork recipe Build separate pedestal trim and side panels below/outside the functional stepped surfaces. A small title plaque nearby is safer than adding another layer to the sloped top. Use broad, calm material regions around the numerical display. Do not add a glass lid across the controls: transparency does not remove a prop's box collider. Preserve the native labels and use custom signage only for the game title or visual theme. Never bake a target, win chance or result into the texture. Do not add fake numbered dice as if their physical landing determines the paid result; the native presentation is driven by game state. ## Review and AI brief Review minimum, middle and maximum target positions, both Flip directions, idle and settled display states, and the result marker at both ends. Keep the full slider accessible in portrait view. Merely opening Settings or inspecting artwork should not require placing a wager. ```text Get game_skin_contract for dice and download my current world draft. Build an original [theme] replacement body in Blender using the reference socket measurements and the preserved gameplay regions described in this guide. Upload static body/button assets; bind only the listed control/part sockets. Keep native labels, game values and collision. Use supported v2 placements, clips and result-motion channels for presentation changes. Save with game_skin_save and the current revision. Inspect the fitted model and report budgets and reviewed states. Do not upload code or publish via MCP. ``` Use [the shared workflow](/model-authoring-workflow/) for collision, normalization and upload limits. ## Reference skin sockets (v1 and v2) Read `game_skin_contract({"game":"dice"})` before saving. The current fingerprint is `b0f6f68ea1a67fd7`. The [live catalog](/game-skin-catalog.json) is authoritative if a copied example differs. The replacement body is fitted to station-local world bounds `[-2.8623114, 0, -1.7320752]` through `[2.8623114, 3.1645429, 1.7887485]`. Width, height and depth are `[5.7246228, 3.1645429, 3.5208237]`. These values already include source scale. Entity scale remains `[1,1,1]`. | Accepted binding slot | Fixed native action | Fixed index / seat | Native label | World-space bounds, minimum → maximum | |---|---|---|---|---| | `control.stake_up` | `stake_up` | None | + | `[-0.9096661, 1.6224991, 1.0508211]` → `[-0.6900915, 1.7244444, 1.5527059]` | | `control.quick` | `quick` | None | BET | `[-0.4469911, 1.6224991, 1.0508211]` → `[0.4469911, 1.7244444, 1.5527059]` | | `control.settings` | `settings` | None | BET SIZE | `[-2.3212169, 1.6224991, 1.0508211]` → `[-1.5683898, 1.7244444, 1.5527059]` | | `control.flip` | `flip` | None | FLIP | `[1.6154415, 1.6224991, 0.92535]` → `[2.3682685, 1.7244445, 1.678177]` | | `control.settings_2` | `settings` | None | SETTINGS | `[0.6273559, 1.6224991, 1.0508211]` → `[1.4742864, 1.7244444, 1.5527059]` | | `control.stake_down` | `stake_down` | None | − | `[-1.239028, 1.6224991, 1.0508211]` → `[-1.0194534, 1.7244444, 1.5527059]` | Only `slot` and the converted model `asset` hash go in each binding. Action, index and seat columns explain platform behavior; **do not copy them into uploaded JSON**. All listed sockets are optional visual overrides. Omitted sockets retain native meshes. Repeated Settings actions are distinct physical sockets and must use the exact listed ID. The catalog provides exact mesh-local `localBounds` for fitting and the full `matrixSource` for native orientation. Optional static surface: `part.playing_surface`, native reference `top`, world bounds `[-2.6348947, 1.4429186, -1.5213381]` through `[2.6348947, 1.4711496, 1.3958669]`. Its replacement does not move cards, the animation rig or the interaction proxy. Save a skin with `game: "dice"`, its current fingerprint, a converted `body` hash and the chosen `bindings`. Apply it only to existing `dice:` entities. Declare each binding in the skin manifest. Follow [the exact manifest and fitting rules](/game-skin-contract/) and [the export workflow](/model-authoring-workflow/). ## V2 layout and animation Fetch `game_skin_contract({"game":"dice"})`. Use `presentation.targets` to position the body, complete display and each listed physical control. Control labels and clickable proxies follow their target; action/index/seat identity stays the same. Numeric `idle` and `result` clips are supported. Use a `result` clip on `display` to animate the live presentation; this game has no separate card/coin/ball motion channel. Reference dimensions above describe the neutral layout before v2 placement. See the [exact fields, transforms and limits](/game-skin-contract/). --- # Drago Tower model guide Source: https://docs.betworld.gg/game-model-dragontower/ [Read as Markdown](/raw/game-model-dragontower.md) · [All game guides](/betting-models/) · [Measured native reference](/game-model-reference.json) ## Replacement skin support This game supports the [v2 skin contract](/game-skin-contract/). Replace the visible body and the exact named physical meshes listed at the end of this page. Use the surround and trim suggestions below to add matching scenery. Preserve the functional regions and state-dependent clearances described here. ## Station identity Use asset `dragontower`, IDs `dragontower:0` through `dragontower:4`, floor elevation Y = 0–64 and scale `[1,1,1]`. The game is labeled Drago Tower in the UI. Its root is `dragontower` in the native game library. Treat it as an upright board with a dynamic tile arrangement. Do not model a fixed ladder over the face based on one concept image. The current native reference contains the geometry needed for several column layouts. ## All difficulty layouts The tower has nine rows. The current configurations are: | Difficulty | Tiles per row | Safe tiles per row | |---|---:|---:| | EASY | 4 | 3 | | MEDIUM | 3 | 2 | | HARD | 2 | 1 | | EXPERT | 3 | 1 | | MASTER | 4 | 1 | Names such as `d4_r0_t0`, `d3_r0_t0` and `d2_r0_t0` identify native reference tiles for the four-, three- and two-column arrangements. The suffixes identify row and column; they are not executable commands. Only the active difficulty's arrangement is shown. Preserve the union of every layout's space, including the top and bottom rows. ## Controls and animation areas | Region | Function | Preserve | |---|---|---| | Active row tiles | Choose a tile at the current step | The full row width and visible feedback | | Other rows | Progress/history and unreached levels | Keep their visual hierarchy readable | | Native CASH OUT button | Starts a round when idle; cashes out when allowed | The button and its front approach | | Settings | Opens difficulty and stake controls | The complete clickable face | | Status screen | Current game status and return information | All text and numbers | | Revealed tile area | Shows safe/hazard feedback | Space in front of every row | The client only permits choices in the correct row/state. An uploaded ornament cannot create another tile or make an unreached row playable. The primary nearby prompt changes according to the active game. Do not bake “always available” Cashout text or a promised multiplier into custom signage. ## Modeling recipe Make external side pylons, low plinth accents or a title beyond the native upper boundary. Use generous empty space around the tower. A dragon ornament that overlaps only the top row still makes the game difficult to use. A decorative staircase in front can push players out of the intended approach or hide the low control bank. Keep solid decorative pieces separate so their box colliders do not span the front of the board. Position the cabinet near a perimeter with its front facing the room if that suits the layout. Rotate the accompanying rug and props by the same yaw. Check both neighboring cabinets and the straight view from the player's eye height. Use simple, matte material regions around the tiles. Revealed-state colors belong to the native client, so avoid a patterned frame that resembles permanent selected or hazardous cells. Do not add a fixed four-column overlay; it will misalign on HARD, MEDIUM or EXPERT. ## Review matrix Inspect EASY, MEDIUM, HARD, EXPERT and MASTER, not just four-column mode. Include the first row, a middle step, the highest row, a completed/lost round and a cashout state in an authorized preview. Ensure the next available row and status screen can be understood on mobile. Static meshes cannot show this full state matrix by themselves. ## AI brief ```text Get game_skin_contract for dragontower and download my current world draft. Build an original [theme] replacement body in Blender using the reference socket measurements and the preserved gameplay regions described in this guide. Upload static body/button assets; bind only the listed control/part sockets. Keep native labels, game values and collision. Use supported v2 placements, clips and result-motion channels for presentation changes. Save with game_skin_save and the current revision. Inspect the fitted model and report budgets and reviewed states. Do not upload code or publish via MCP. ``` See [the common modeling workflow](/model-authoring-workflow/) for export and draft handling. ## Reference skin sockets (v1 and v2) Read `game_skin_contract({"game":"dragontower"})` before saving. The current fingerprint is `924683f5f720ea2e`. The [live catalog](/game-skin-catalog.json) is authoritative if a copied example differs. The replacement body is fitted to station-local world bounds `[-4.1640751, 0, -1.1684503]` through `[4.1640751, 10.5709474, 1.9840131]`. Width, height and depth are `[8.3281503, 10.5709474, 3.1524634]`. These values already include source scale. Entity scale remains `[1,1,1]`. | Accepted binding slot | Fixed native action | Fixed index / seat | Native label | World-space bounds, minimum → maximum | |---|---|---|---|---| | `control.cashout` | `cashout` | None | CASH OUT | `[-3.7641353, 1.6746155, 0.9163082]` → `[-2.885837, 2.0004075, 1.7910646]` | | `control.settings` | `settings` | None | SETTINGS | `[2.885837, 1.6949118, 0.9920556]` → `[3.7641353, 1.9801109, 1.7153171]` | Only `slot` and the converted model `asset` hash go in each binding. Action, index and seat columns explain platform behavior; **do not copy them into uploaded JSON**. All listed sockets are optional visual overrides. Omitted sockets retain native meshes. Repeated Settings actions are distinct physical sockets and must use the exact listed ID. The catalog provides exact mesh-local `localBounds` for fitting and the full `matrixSource` for native orientation. Save a skin with `game: "dragontower"`, its current fingerprint, a converted `body` hash and the chosen `bindings`. Apply it only to existing `dragontower:` entities. Declare each binding in the skin manifest. Follow [the exact manifest and fitting rules](/game-skin-contract/) and [the export workflow](/model-authoring-workflow/). ## V2 layout and animation Fetch `game_skin_contract({"game":"dragontower"})`. Use `presentation.targets` to position the body, complete display and each listed physical control. Control labels and clickable proxies follow their target; action/index/seat identity stays the same. Numeric `idle` and `result` clips are supported. Use a `result` clip on `display` to animate the live presentation; this game has no separate card/coin/ball motion channel. Reference dimensions above describe the neutral layout before v2 placement. See the [exact fields, transforms and limits](/game-skin-contract/). --- # Keno model guide Source: https://docs.betworld.gg/game-model-keno/ [Read as Markdown](/raw/game-model-keno.md) · [All game guides](/betting-models/) · [Measured native reference](/game-model-reference.json) ## Replacement skin support This game supports the [v2 skin contract](/game-skin-contract/). Replace the visible body and the exact named physical meshes listed at the end of this page. Use the surround and trim suggestions below to add matching scenery. Preserve the functional regions and state-dependent clearances described here. ## Native station Use `keno:0` through `keno:4`, asset `keno`, floor elevation Y = 0–64 and unit entity scale. The root is `keno` in the game collection. It is a wide upright cabinet; measure its current world-space bounds before fitting it beside another board. Leave an approach far enough back to see the entire grid on a portrait display. The live number area contains **40 numbers in eight columns and five rows**. Players can select up to ten numbers. Native references `tile_0`…`tile_39` are zero-based geometry identifiers; the game selections are numbers **1…40**. Do not confuse these conventions when reading the reference. ## Required visible areas | Region | Native purpose | |---|---| | Number grid | Select/unselect numbers and display drawn outcomes | | Bet | Starts the configured round; requires a valid number selection | | Random | Uses the platform's number-selection behavior | | Stake − / + | Adjust the next stake when allowed | | Settings | Opens supported risk, stake and related bet controls | | Paytable area | Reflects the current number count and risk configuration | | Status strip | Instructions, reveal progress, hit count and result | Read physical button positions from `games.keno.controls` and the current grid and screen envelope from its reference nodes/runtime mounts. Do not build a substitute Random button or invent a `random` binding for a prop. The functional control stays native. ## Artwork layout Frame the outside of the native cabinet with separate panels or a nearby sign. Keep all eight columns visible. Centering a decorative opening on the middle six columns is not sufficient. Keep the entire screen above the numbers clear: it contains a live payout table, not just a decorative title area. The payout table changes when selection count or risk changes. Never engrave a fixed payout table into new artwork as the game's authoritative information. Preserve the native distinction between selected numbers, drawn numbers and selected hits; a custom background should not reuse those state colors in a confusing pattern. Place large boards on the room perimeter when practical and face them inward using yaw. Use separate solid side decorations and check their collision boxes. A planter at the front corner may hide the outermost column even if it does not overlap the cabinet itself. Leave adequate room for the full portrait-phone viewing position, not just a character standing immediately in front of the base. ## State review Check an empty selection, several selected numbers, the maximum selection, and the live paytable at different selection counts/risk settings. During a draw, the native client reveals outcomes progressively and displays matches. Inspect both the lowest and highest numbered rows. At completion, the result summary and hit count must remain readable. In a Blender-only review, mark the number rectangle and paytable as protected placeholders. They will be generated by the client. To inspect active states, use an authorized preview or owner-authorized session; creating art does not authorize wagering. Common problems include a central ornament spanning the grid, a title board hiding the paytable, and front furniture forcing the viewing camera too close. Another is labeling custom tiles 0–39, which does not match the player-facing 1–40 numbering. ## AI brief ```text Get game_skin_contract for keno and download my current world draft. Build an original [theme] replacement body in Blender using the reference socket measurements and the preserved gameplay regions described in this guide. Upload static body/button assets; bind only the listed control/part sockets. Keep native labels, game values and collision. Use supported v2 placements, clips and result-motion channels for presentation changes. Save with game_skin_save and the current revision. Inspect the fitted model and report budgets and reviewed states. Do not upload code or publish via MCP. ``` Continue with [export and upload](/model-authoring-workflow/); replacement cabinets use [skin contract v2](/game-skin-contract/). ## Reference skin sockets (v1 and v2) Read `game_skin_contract({"game":"keno"})` before saving. The current fingerprint is `11b132575f081153`. The [live catalog](/game-skin-catalog.json) is authoritative if a copied example differs. The replacement body is fitted to station-local world bounds `[-4.5091205, 0, -1.1684503]` through `[4.5091205, 9.0401985, 2.3525847]`. Width, height and depth are `[9.018241, 9.0401985, 3.521035]`. These values already include source scale. Entity scale remains `[1,1,1]`. | Accepted binding slot | Fixed native action | Fixed index / seat | Native label | World-space bounds, minimum → maximum | |---|---|---|---|---| | `control.stake_up` | `stake_up` | None | + | `[-3.7406096, 1.7476827, 1.5340446]` → `[-3.4112477, 1.9273402, 1.8634197]` | | `control.quick` | `quick` | None | BET | `[-4.2192821, 1.6928011, 0.5293448]` → `[-3.4815115, 1.9822218, 1.2683618]` | | `control.random` | `random` | None | RANDOM | `[3.4815115, 1.6928011, 0.5293448]` → `[4.2192821, 1.9822218, 1.2683618]` | | `control.settings` | `settings` | None | SETTINGS | `[3.5445608, 1.7322574, 1.5078444]` → `[4.1562328, 1.9427655, 1.9523555]` | | `control.stake_down` | `stake_down` | None | − | `[-4.2424942, 1.7476827, 1.5340446]` → `[-3.9131324, 1.9273402, 1.8634197]` | Only `slot` and the converted model `asset` hash go in each binding. Action, index and seat columns explain platform behavior; **do not copy them into uploaded JSON**. All listed sockets are optional visual overrides. Omitted sockets retain native meshes. Repeated Settings actions are distinct physical sockets and must use the exact listed ID. The catalog provides exact mesh-local `localBounds` for fitting and the full `matrixSource` for native orientation. Save a skin with `game: "keno"`, its current fingerprint, a converted `body` hash and the chosen `bindings`. Apply it only to existing `keno:` entities. Declare each binding in the skin manifest. Follow [the exact manifest and fitting rules](/game-skin-contract/) and [the export workflow](/model-authoring-workflow/). ## V2 layout and animation Fetch `game_skin_contract({"game":"keno"})`. Use `presentation.targets` to position the body, complete display and each listed physical control. Control labels and clickable proxies follow their target; action/index/seat identity stays the same. Numeric `idle` and `result` clips are supported. Use a `result` clip on `display` to animate the live presentation; this game has no separate card/coin/ball motion channel. Reference dimensions above describe the neutral layout before v2 placement. See the [exact fields, transforms and limits](/game-skin-contract/). --- # Limbo model guide Source: https://docs.betworld.gg/game-model-limbo/ [Read as Markdown](/raw/game-model-limbo.md) · [All game guides](/betting-models/) · [Measured native reference](/game-model-reference.json) ## Replacement skin support This game supports the [v2 skin contract](/game-skin-contract/). Replace the visible body and the exact named physical meshes listed at the end of this page. Use the surround and trim suggestions below to add matching scenery. Preserve the functional regions and state-dependent clearances described here. ## Native station Use asset `limbo`, IDs `limbo:0` through `limbo:4`, floor elevation Y = 0–64 and scale `[1,1,1]`. The native root is `limbo` in the game library. It is a compact machine with a low control deck and a wide result display. Keep its supplied proportions; do not enlarge it into a wall screen by scaling the game entity. Read `games.limbo.controls` for the actual buttons and `runtimeMounts.nodes.screen` for the display. The live display follows the screen's sloped bounds. A front-facing rectangle guessed from a screenshot will not necessarily align with it. ## Controls and live content | Region | Function | |---|---| | Bet | Starts the configured round | | Stake − / + | Adjusts the next stake when allowed | | Target | Opens native settings for the target configuration | | Settings | Opens the supported bet controls | | Main multiplier display | Presents the game result | | Target and stake readouts | Show the current configuration alongside the result | Target is not an uploaded-model field, and a custom mesh named `target` does not become an input. The native client owns result animation, state colors and text. Limbo is not Crash: do not add a Cashout control or a live-flight graph implying that the player can stop a round during its reveal. ## Modeling approach Add separate side caps, a modest pedestal accent or a title sign outside the display's bounds. Keep the native cabinet, screen and control deck. Use the scene's actual body-height reference to assess readability. Raising the whole cabinet off the floor or stretching it vertically changes the relationship to the player's camera and is not supported for games. Keep the display opening wide enough for the central multiplier **and** the target and stake areas to either side. A sign or border that frames only the center number removes useful information. Avoid glossy surfaces directly around the readout if they compete with it visually; roughness and color belong in the static material. Use separate solid props and keep their bounding boxes away from the standing approach. Do not merge a hollow arch into one collider or place another machine immediately in front. Align the rug and decorative pieces with the game's yaw when arranging a row. ## State review Inspect the idle configuration, changing result presentation, completed return/loss state and a long multiplier string in an authorized preview. Check that all numbers fit inside the original screen opening, including edge readouts. The artwork must not contain a fixed multiplier or a decorative green “win” state that conflicts with the actual result. Review from standing eye height, obliquely, and in a portrait viewport. Static Blender renders do not include the live canvas automatically, so use a temporary protected rectangle for layout and confirm the final native display in the client. ## AI brief ```text Get game_skin_contract for limbo and download my current world draft. Build an original [theme] replacement body in Blender using the reference socket measurements and the preserved gameplay regions described in this guide. Upload static body/button assets; bind only the listed control/part sockets. Keep native labels, game values and collision. Use supported v2 placements, clips and result-motion channels for presentation changes. Save with game_skin_save and the current revision. Inspect the fitted model and report budgets and reviewed states. Do not upload code or publish via MCP. ``` See [the complete authoring workflow](/model-authoring-workflow/) for transfer and publication. ## Reference skin sockets (v1 and v2) Read `game_skin_contract({"game":"limbo"})` before saving. The current fingerprint is `e67cd6018aa91874`. The [live catalog](/game-skin-catalog.json) is authoritative if a copied example differs. The replacement body is fitted to station-local world bounds `[-2.8623114, 0, -1.7095449]` through `[2.8623114, 3.0583601, 1.7887485]`. Width, height and depth are `[5.7246228, 3.0583601, 3.4982934]`. These values already include source scale. Entity scale remains `[1,1,1]`. | Accepted binding slot | Fixed native action | Fixed index / seat | Native label | World-space bounds, minimum → maximum | |---|---|---|---|---| | `control.stake_up` | `stake_up` | None | + | `[-0.7371432, 1.6224991, 1.0508211]` → `[-0.5175686, 1.7244444, 1.5527059]` | | `control.quick` | `quick` | None | BET | `[-0.2352585, 1.6224991, 1.0508211]` → `[0.8626144, 1.7244444, 1.5527059]` | | `control.settings` | `settings` | None | SETTINGS | `[-2.4310042, 1.6224991, 1.0508211]` → `[-1.4899703, 1.7244444, 1.5527059]` | | `control.settings_2` | `settings` | None | TARGET | `[1.3409732, 1.6224991, 1.0508211]` → `[2.3604265, 1.7244444, 1.5527059]` | | `control.stake_down` | `stake_down` | None | − | `[-1.082189, 1.6224991, 1.0508211]` → `[-0.8626144, 1.7244444, 1.5527059]` | Only `slot` and the converted model `asset` hash go in each binding. Action, index and seat columns explain platform behavior; **do not copy them into uploaded JSON**. All listed sockets are optional visual overrides. Omitted sockets retain native meshes. Repeated Settings actions are distinct physical sockets and must use the exact listed ID. The catalog provides exact mesh-local `localBounds` for fitting and the full `matrixSource` for native orientation. Optional static surface: `part.playing_surface`, native reference `top`, world bounds `[-2.6348947, 1.4429186, -1.5213381]` through `[2.6348947, 1.4711496, 1.3958669]`. Its replacement does not move cards, the animation rig or the interaction proxy. Save a skin with `game: "limbo"`, its current fingerprint, a converted `body` hash and the chosen `bindings`. Apply it only to existing `limbo:` entities. Declare each binding in the skin manifest. Follow [the exact manifest and fitting rules](/game-skin-contract/) and [the export workflow](/model-authoring-workflow/). ## V2 layout and animation Fetch `game_skin_contract({"game":"limbo"})`. Use `presentation.targets` to position the body, complete display and each listed physical control. Control labels and clickable proxies follow their target; action/index/seat identity stays the same. Numeric `idle` and `result` clips are supported. Use a `result` clip on `display` to animate the live presentation; this game has no separate card/coin/ball motion channel. Reference dimensions above describe the neutral layout before v2 placement. See the [exact fields, transforms and limits](/game-skin-contract/). --- # Mines model guide Source: https://docs.betworld.gg/game-model-mines/ [Read as Markdown](/raw/game-model-mines.md) · [All game guides](/betting-models/) · [Measured native reference](/game-model-reference.json) ## Replacement skin support This game supports the [v2 skin contract](/game-skin-contract/). Replace the visible body and the exact named physical meshes listed at the end of this page. Use the surround and trim suggestions below to add matching scenery. Preserve the functional regions and state-dependent clearances described here. ## Station and layout Use asset `mines`, IDs `mines:0` through `mines:4`, floor elevation Y = 0–64 and scale `[1,1,1]`. The native root is `mines`. This is a large upright game: plan its whole frontage and a clear standing area before adding scenery. Perimeter placement facing inward is often easier to read than a tall board in the center of a walkway. Fetch `games.mines` from the current reference JSON. The native `tile_0` through `tile_24` geometry defines the baseline board envelope, but **the live game is not fixed to 25 tiles**. The client lays out 3 × 3 through 8 × 8 grids inside that area. Native mesh names are reference data, not a fixed creator-defined number of playable cells. ## Protected controls and displays | Region | Runtime behavior | Artwork requirement | |---|---|---| | Full tile rectangle | Reveals a chosen cell during an active game | Leave every edge and the entire face clear for all grid sizes | | Native CASH OUT button | Starts a game when idle; cashes out when the active state permits it | Retain the button, approach and state-dependent behavior | | Settings button | Opens stake, mine count and board-size settings | Keep unobstructed | | Summary screen | Current/next return, stake, mines, remaining gems and status | Preserve the whole display, not just its central number | | Revealed cell volume | Gem/mine artwork extends forward from the grid | Reserve depth in front of the board | The native action metadata for the main button is `cashout`. The client maps it to the correct action in context. It does not cash out before a valid reveal and does not let decorative artwork start or settle a round. The nearby primary prompt also changes from Bet to Cash out. Keep its label/state client-owned. ## Model a surround that works at every size Use separate outside columns, low side accents or a title plaque beyond the native top edge. Avoid a decorative lattice over the grid. A divider aligned to a 5 × 5 screenshot will cross cells on a 3 × 3 or 8 × 8 board. Do not add permanent tile numbers, gems, mines or selected-state colors to custom geometry. The smallest cells occur in the 8 × 8 layout. Leave enough empty space around the face that they remain readable on a portrait phone. Avoid bright emissive trim and high-frequency textures immediately behind the numbers. Do not cover the summary with a custom price/sign; the displayed values depend on the actual game settings and state. As with every prop, a single hollow frame gets a solid box collider. Split side decorations and keep their bounds outside the frontal interaction corridor. Reserve the full approach distance instead of placing another machine directly in front of the grid. Check a neighboring station's camera line too. ## State and clearance review Review minimum, default and maximum board sizes. In an authorized preview, inspect untouched cells, selected/queued feedback, gem reveals, a mine reveal, cashout and completed-round state. A static GLB viewer will not show the live grid layout or reveal pieces; use its bounds as a starting point, not a complete test. A common failure is trim that clears idle tiles but intersects a gem after reveal. Another is a custom base covering the low controls. Correct the decorative piece; native buttons, grid extents and reveal depth are not user-relocatable. ## AI brief ```text Get game_skin_contract for mines and download my current world draft. Build an original [theme] replacement body in Blender using the reference socket measurements and the preserved gameplay regions described in this guide. Upload static body/button assets; bind only the listed control/part sockets. Keep native labels, game values and collision. Use supported v2 placements, clips and result-motion channels for presentation changes. Save with game_skin_save and the current revision. Inspect the fitted model and report budgets and reviewed states. Do not upload code or publish via MCP. ``` Use the [complete workflow](/model-authoring-workflow/) for export, normalization and budgets. ## Reference skin sockets (v1 and v2) Read `game_skin_contract({"game":"mines"})` before saving. The current fingerprint is `c05feb8688027c9c`. The [live catalog](/game-skin-catalog.json) is authoritative if a copied example differs. The replacement body is fitted to station-local world bounds `[-3.7327677, 0, -1.1684503]` through `[3.7327677, 8.4065694, 1.9840131]`. Width, height and depth are `[7.4655354, 8.4065694, 3.1524634]`. These values already include source scale. Entity scale remains `[1,1,1]`. | Accepted binding slot | Fixed native action | Fixed index / seat | Native label | World-space bounds, minimum → maximum | |---|---|---|---|---| | `control.cashout` | `cashout` | None | CASH OUT | `[-3.5445609, 1.6746155, 0.9163082]` → `[-2.6662627, 2.0004075, 1.7910646]` | | `control.settings` | `settings` | None | SETTINGS | `[2.6662627, 1.6746155, 0.9163082]` → `[3.5445609, 2.0004075, 1.7910646]` | Only `slot` and the converted model `asset` hash go in each binding. Action, index and seat columns explain platform behavior; **do not copy them into uploaded JSON**. All listed sockets are optional visual overrides. Omitted sockets retain native meshes. Repeated Settings actions are distinct physical sockets and must use the exact listed ID. The catalog provides exact mesh-local `localBounds` for fitting and the full `matrixSource` for native orientation. Save a skin with `game: "mines"`, its current fingerprint, a converted `body` hash and the chosen `bindings`. Apply it only to existing `mines:` entities. Declare each binding in the skin manifest. Follow [the exact manifest and fitting rules](/game-skin-contract/) and [the export workflow](/model-authoring-workflow/). ## V2 layout and animation Fetch `game_skin_contract({"game":"mines"})`. Use `presentation.targets` to position the body, complete display and each listed physical control. Control labels and clickable proxies follow their target; action/index/seat identity stays the same. Numeric `idle` and `result` clips are supported. Use a `result` clip on `display` to animate the live presentation; this game has no separate card/coin/ball motion channel. Reference dimensions above describe the neutral layout before v2 placement. See the [exact fields, transforms and limits](/game-skin-contract/). --- # Plinko model guide Source: https://docs.betworld.gg/game-model-plinko/ [Read as Markdown](/raw/game-model-plinko.md) · [All game guides](/betting-models/) · [Measured native reference](/game-model-reference.json) ## Replacement skin support This game supports the [v2 skin contract](/game-skin-contract/). Replace the visible body and the exact named physical meshes listed at the end of this page. Use the surround and trim suggestions below to add matching scenery. Preserve the functional regions and state-dependent clearances described here. ## Station and footprint Use `plinko:0` through `plinko:4`, asset `plinko`, floor elevation Y = 0–64 and scale `[1,1,1]`. The native root is `plinko`. This is a tall, wide board with a front-side player approach and low controls. Measure the whole cabinet before placing it, not only the triangular peg field. A perimeter location facing the room is a useful starting point. Keep the player's viewing area clear far enough back to see the board on a phone. Rotate all side decorations and walkway pieces with the station; there is no automatic parent relationship between world entities. ## Functional regions and anchors | Region | Keep available | |---|---| | Drop button | The native primary action and its standing approach | | Settings button | Risk and supported bet configuration | | `ball_spawnpoint` | Empty space at the start of the animated path | | `peg__` | All twelve peg rows and the spaces between them | | `bucket_0` … `bucket_12` | All thirteen ending pockets, especially the outermost pair | | Multiplier strip | Dynamic values for the current risk configuration | The current client builds ball trajectories from these native anchors. The ball visually bounces and rotates along the supplied path. This is platform presentation of an accepted result; creators do not upload a rigid-body simulation or make their own pegs determine payouts. Native physical controls are measured in `games.plinko.controls`. Ball, peg and pocket mounts are in `runtimeMounts`. The live multiplier strip occupies a 6.87 × 0.44 plane at `[0,0.20,0.345]` in source-scaled station coordinates: multiply these values by the reference scale when reasoning in world units. The strip is a generated overlay, so a bare GLB viewer will not show all current values. ## Buildable visual changes Add separate outer columns, a side emblem, a base trim piece outside the pocket mouth or a sign beyond the top edge. Keep the original board, pegs, ball and buttons. Do not install an ornamental crossbar over the field: even if it misses every peg, a ball can pass through the space between them. Do not add a second transparent front pane and assume it is non-interactive. Uploaded props have box collision, and the extra geometry can obscure hit targets or create overlapping transparent layers. Use the existing board face and place artwork beyond it. Do not bake multipliers into a texture or engrave fixed payouts into custom pocket labels. Risk changes the native display. Keep the bottom strip fully visible from standing height; a decorative pedestal lip often hides it when viewed from above. ## Animation and layout review Inspect paths to both extreme pockets and the middle, with room in front of the board for the ball's full visible shape. Multiple drops can be visible at once; a single center-path screenshot is insufficient. Check the spawn area, each row, bottom pockets and live multiplier strip in an authorized preview. Look from the normal approach in portrait and landscape. Ensure a neighboring board's columns or props do not cross the view. Keep the Drop and Settings controls readable even when looking down toward the lowest pockets. The nearby primary prompt uses the current key binding and touch equivalent; do not hardcode keyboard instructions on the artwork. ## AI brief ```text Get game_skin_contract for plinko and download my current world draft. Build an original [theme] replacement body in Blender using the reference socket measurements and the preserved gameplay regions described in this guide. Upload static body/button assets; bind only the listed control/part sockets. Keep native labels, game values and collision. Use supported v2 placements, clips and result-motion channels for presentation changes. Save with game_skin_save and the current revision. Inspect the fitted model and report budgets and reviewed states. Do not upload code or publish via MCP. ``` Read [the export workflow](/model-authoring-workflow/) before uploading. ## Reference skin sockets (v1 and v2) Read `game_skin_contract({"game":"plinko"})` before saving. The current fingerprint is `6f0f7d703a2ac31d`. The [live catalog](/game-skin-catalog.json) is authoritative if a copied example differs. The replacement body is fitted to station-local world bounds `[-7.2694868, -0.0392095, -1.0900309]` through `[7.2694868, 9.8181204, 1.9761711]`. Width, height and depth are `[14.5389735, 9.8573299, 3.066202]`. These values already include source scale. Entity scale remains `[1,1,1]`. | Accepted binding slot | Fixed native action | Fixed index / seat | Native label | World-space bounds, minimum → maximum | |---|---|---|---|---| | `control.quick` | `quick` | None | DROP | `[-7.0263863, 1.6624376, 0.6983368]` → `[-6.0539847, 2.0125853, 1.6639901]` | | `control.settings` | `settings` | None | SETTINGS | `[6.0539847, 1.6624376, 0.6983368]` → `[7.0263863, 2.0125853, 1.6639901]` | Only `slot` and the converted model `asset` hash go in each binding. Action, index and seat columns explain platform behavior; **do not copy them into uploaded JSON**. All listed sockets are optional visual overrides. Omitted sockets retain native meshes. Repeated Settings actions are distinct physical sockets and must use the exact listed ID. The catalog provides exact mesh-local `localBounds` for fitting and the full `matrixSource` for native orientation. Save a skin with `game: "plinko"`, its current fingerprint, a converted `body` hash and the chosen `bindings`. Apply it only to existing `plinko:` entities. Declare each binding in the skin manifest. Follow [the exact manifest and fitting rules](/game-skin-contract/) and [the export workflow](/model-authoring-workflow/). ## V2 layout and animation Fetch `game_skin_contract({"game":"plinko"})`. Use `presentation.targets` to position the body, complete display and each listed physical control. Control labels and clickable proxies follow their target; action/index/seat identity stays the same. Numeric `idle` and `result` clips are supported. Its result-motion channels are `plinko_drop`. Use the per-result progress and zero endpoint offsets described in the contract. Reference dimensions above describe the neutral layout before v2 placement. See the [exact fields, transforms and limits](/game-skin-contract/). --- # Doubler display model guide Source: https://docs.betworld.gg/game-model-roulette/ [Read as Markdown](/raw/game-model-roulette.md) · [All game guides](/betting-models/) · [Measured native reference](/game-model-reference.json) ## Replacement skin support This game supports the [v2 skin contract](/game-skin-contract/). Replace the visible body and the exact named physical meshes listed at the end of this page. Use the surround and trim suggestions below to add matching scenery. Preserve the functional regions and state-dependent clearances described here. ## Doubler is the `roulette` asset Use `{"id":"roulette:0","kind":"game","asset":"roulette","position":[0,0,0],"yaw":0,"scale":[1,1,1],"color":"#ffffff"}` as the native station, with a position that fits your layout. There is one permitted Doubler station per creator world. Do not invent `doubler:0` or an ordinary roulette wheel asset. Its native root is `roulette` in the **props/display library**, not the card-table library. The library geometry uses a display-specific source-to-world scale, currently **1.05**. The bridge applies it. Do not use the shared card-table scale or change the entity scale to compensate. ## Screen and interaction regions The main screen plane is 9.36 × 4.68 source units, centered at `[0,3.6,0.31]` before the display scale and station transform. Preserve the entire screen rectangle and the slightly forward overlays. Exact display measurements are also in [model-proportions.json](/model-proportions.json). | Region | Native purpose | |---|---| | Reel strip and marker | Shows the round's moving selection and outcome | | Round status / countdown | Shows when betting is open or the round is progressing | | Red / Green / Black / Bait columns | The four native outcome selections and their bet areas | | Stake and settings area | Opens/configures the supported bet controls | | Player rows | Shows participants and results; some regions open player information | The reel strip is centered above the betting columns; the betting overlay is centered near `[0,1.90,0.38]` in display-source space. These are live client layers in front of the static display body. Do not add a glass pane, custom billboard face or decorative bars across them. The generated native reference can correctly show an empty `controls` array here: this game's clickable regions are generated by the display code, not mesh-based physical buttons. ## Artwork recipe Create separate outside frame pillars, base end-caps or a sign above the native cabinet. Keep all four betting columns visible and reachable. Use an opening sized for the full display, not just the animated reel. A narrow opening that preserves the center will still hide a side choice or the settings corner. Avoid a single giant hollow frame: its bounding-box collider may span the screen approach. Split solid pieces and keep their bounds outside the player's route. The lower betting/player region must be visible from standing height and on portrait phones. Do not place shrubs or a thick front counter across it. Do not bake player names, a payout table, countdown, winning color or reel result into the art. These values are live. Decorative color stripes should not look like additional betting choices. The runtime owns selection semantics and wager handling; your mesh cannot change the reel order or accepted outcomes. ## Shared-state review Review the open-betting display, waiting state, moving reel and settled result in an authorized preview. Verify that the outcome marker is visible throughout the reel animation and that all selection columns remain separate. Check the lower participant area as well as the title. A screenshot of an empty screen is insufficient. The nearby prompt may open bet controls rather than silently choose an outcome. Keep instructions generic and let the client show the player's current key binding or touch action. ## AI brief ```text Get game_skin_contract for roulette and download my current world draft. Build an original [theme] replacement body in Blender using the reference socket measurements and the preserved gameplay regions described in this guide. Upload static body/button assets; bind only the listed control/part sockets. Keep native labels, game values and collision. Use supported v2 placements, clips and result-motion channels for presentation changes. Save with game_skin_save and the current revision. Inspect the fitted model and report budgets and reviewed states. Do not upload code or publish via MCP. ``` Follow [the common workflow](/model-authoring-workflow/) for transforms, budgets and publication. ## Reference skin sockets (v1 and v2) Read `game_skin_contract({"game":"roulette"})` before saving. The current fingerprint is `d4e49f283e62dbaf`. The [live catalog](/game-skin-catalog.json) is authoritative if a copied example differs. The replacement body is fitted to station-local world bounds `[-5.7434999, 0, -0.819]` through `[5.7434999, 7.6440002, 0.987]`. Width, height and depth are `[11.4869999, 7.6440002, 1.806]`. These values already include source scale. Entity scale remains `[1,1,1]`. There are **no physical-button replacement sockets** for this game. Use `bindings: []`. The platform generates all clickable screen regions, their labels and state-dependent availability. The body can be replaced; the interactive display supports v2 placement and clips, with live content supplied by Betworld. Save a skin with `game: "roulette"`, its current fingerprint, a converted `body` hash and the chosen `bindings`. Apply it only to existing `roulette:` entities. Declare each binding in the skin manifest. Follow [the exact manifest and fitting rules](/game-skin-contract/) and [the export workflow](/model-authoring-workflow/). ## V2 layout and animation Fetch `game_skin_contract({"game":"roulette"})`. Use `presentation.targets` to position the body, complete display and each listed physical control. Control labels and clickable proxies follow their target; action/index/seat identity stays the same. Numeric `idle` and `result` clips are supported. Use a `result` clip on `display` to animate the live presentation; this game has no separate card/coin/ball motion channel. Reference dimensions above describe the neutral layout before v2 placement. See the [exact fields, transforms and limits](/game-skin-contract/). --- # Video Poker model guide Source: https://docs.betworld.gg/game-model-videopoker/ [Read as Markdown](/raw/game-model-videopoker.md) · [All game guides](/betting-models/) · [Measured native reference](/game-model-reference.json) ## Replacement skin support This game supports the [v2 skin contract](/game-skin-contract/). Replace the visible body and the exact named physical meshes listed at the end of this page. Use the surround and trim suggestions below to add matching scenery. Preserve the functional regions and state-dependent clearances described here. ## Cabinet identity Use `videopoker:0` through `videopoker:4`, asset `videopoker`, floor elevation Y = 0–64 and scale `[1,1,1]`. The native root is `videopoker` in the game library. Use its current `controls` array for the physical button bounds; the cabinet already has an authored control deck. Do not confuse source GLB units with generated UI units. The native body uses the game source scale; the live poker screen below is specified directly in station-local world units. The bridge handles the body scale. Applying that scale again to the screen measurements misaligns the design. ## Controls to preserve | Native region | Behavior | |---|---| | Deal / Draw | Deals the first five cards, then draws replacements according to the hand state | | Five physical Hold buttons | Correspond to card indices 0–4 from left to right | | Five clickable card regions | Also toggle the corresponding Hold selection | | Stake − / + | Configure a future stake when allowed | | Settings | Opens the native bet controls | | Paytable | Opens the supported settings/paytable interface | | Screen | Shows the paytable, five cards, held state, instructions and result | Hold is a per-card selection, not a new wager. Preserve the alignment between each button and its card. After settlement, Hold controls should no longer imply an editable hand; the client controls availability and highlighting. Do not add a sixth card slot or separate fake Draw button. ## Exact live screen reference The main screen center is `[0,2.80,0.51]`, width 3.82 and height 2.865, in **station-local world coordinates, Y up**. Its source canvas is 960 × 720, a 4:3 aspect ratio. Keep the whole rectangle visible, including the upper paytable and lower status text. For each `i` in 0…4, the transparent card interaction target has: ```text Get game_skin_contract for videopoker and download my current world draft. Build an original [theme] replacement body in Blender using the reference socket measurements and the preserved gameplay regions described in this guide. Upload static body/button assets; bind only the listed control/part sockets. Keep native labels, game values and collision. Use supported v2 placements, clips and result-motion channels for presentation changes. Save with game_skin_save and the current revision. Inspect the fitted model and report budgets and reviewed states. Do not upload code or publish via MCP. ``` Use [betting-interfaces.json](/betting-interfaces.json) for the same values as structured data. Its historical generated `deck` describes a fallback deck that is hidden when the authored native buttons exist. For the **current physical controls**, use [game-model-reference.json](/game-model-reference.json), not that fallback deck. ## Build the surround Model separate side panels, base accents or a small marquee beyond the existing bezel. Keep the native cabinet visible. Avoid an all-in-one arch: its box collider can fill the player's access space. A thick new bezel can overlap the first/last card or the upper paytable even if the central cards look fine. Use restrained texture detail near the cards. Do not bake sample cards, a winning hand, held indicators or a payout table into the decorative texture. Betworld renders the current cards and authoritative display content. A local Blender animation is not exported as a replacement card-flip animation. ## Review states and common failures Inspect idle card backs, the dealt hand, a mixture of held and unheld cards, drawing and a completed result in an authorized preview. The live card flip stays on the native screen, while physical Hold buttons highlight independently. Both interaction routes must remain visible and reachable. Check the entire 4:3 screen on a narrow phone, with room for the nearby controls prompt. Typical failures are a marquee covering the paytable, side trim covering card 0 or 4, a deep front panel hiding the Hold bank, or double scaling the cabinet. Moving custom artwork fixes these; moving native buttons is not supported. ## AI brief ```text Get game_skin_contract for videopoker and download my current world draft. Build an original [theme] replacement body in Blender using the reference socket measurements and the preserved gameplay regions described in this guide. Upload static body/button assets; bind only the listed control/part sockets. Keep native labels, game values and collision. Use supported v2 placements, clips and result-motion channels for presentation changes. Save with game_skin_save and the current revision. Inspect the fitted model and report budgets and reviewed states. Do not upload code or publish via MCP. ``` ## Reference skin sockets (v1 and v2) Read `game_skin_contract({"game":"videopoker"})` before saving. The current fingerprint is `9068759bd813612a`. The [live catalog](/game-skin-catalog.json) is authoritative if a copied example differs. The replacement body is fitted to station-local world bounds `[-2.3212169, 0, -1.2939215]` through `[2.3212169, 5.6932551, 1.984013]`. Width, height and depth are `[4.6424338, 5.6932551, 3.2779346]`. These values already include source scale. Entity scale remains `[1,1,1]`. | Accepted binding slot | Fixed native action | Fixed index / seat | Native label | World-space bounds, minimum → maximum | |---|---|---|---|---| | `control.stake_up` | `stake_up` | None | + | `[-0.6665657, 1.3088213, 1.3096055]` → `[-0.4313072, 1.4107667, 1.7958063]` | | `control.quick` | `quick` | None | DEAL / DRAW | `[-0.2431004, 1.3088213, 1.3096055]` → `[0.9331919, 1.4107667, 1.7958063]` | | `control.hold_1` | `hold` | index 1 | HOLD | `[-0.998211, 1.3088213, 0.4940428]` → `[-0.386539, 1.4107667, 0.8861402]` | | `control.hold_2` | `hold` | index 2 | HOLD | `[-0.2978777, 1.3088213, 0.4940428]` → `[0.3137943, 1.4107667, 0.8861402]` | | `control.hold_3` | `hold` | index 3 | HOLD | `[0.4024557, 1.3088213, 0.4940428]` → `[1.0141277, 1.4107667, 0.8861402]` | | `control.hold_4` | `hold` | index 4 | HOLD | `[1.102789, 1.3088213, 0.4940428]` → `[1.714461, 1.4107667, 0.8861402]` | | `control.hold_0` | `hold` | index 0 | HOLD | `[-1.6985444, 1.3088213, 0.4940428]` → `[-1.0868724, 1.4107667, 0.8861402]` | | `control.settings` | `settings` | None | PAYTABLE | `[-2.0467486, 1.3088213, 1.3096055]` → `[-1.2782376, 1.4107667, 1.7958063]` | | `control.settings_2` | `settings` | None | SETTINGS | `[1.3723411, 1.3088213, 1.3096055]` → `[2.1408521, 1.4107667, 1.7958063]` | | `control.stake_down` | `stake_down` | None | − | `[-1.0272953, 1.3088213, 1.3096055]` → `[-0.7920368, 1.4107667, 1.7958063]` | Only `slot` and the converted model `asset` hash go in each binding. Action, index and seat columns explain platform behavior; **do not copy them into uploaded JSON**. All listed sockets are optional visual overrides. Omitted sockets retain native meshes. Repeated Settings actions are distinct physical sockets and must use the exact listed ID. The catalog provides exact mesh-local `localBounds` for fitting and the full `matrixSource` for native orientation. Save a skin with `game: "videopoker"`, its current fingerprint, a converted `body` hash and the chosen `bindings`. Apply it only to existing `videopoker:` entities. Declare each binding in the skin manifest. Follow [the exact manifest and fitting rules](/game-skin-contract/) and [the export workflow](/model-authoring-workflow/). ## V2 layout and animation Fetch `game_skin_contract({"game":"videopoker"})`. Use `presentation.targets` to position the body, complete display and each listed physical control. Control labels and clickable proxies follow their target; action/index/seat identity stays the same. Numeric `idle` and `result` clips are supported. Use a `result` clip on `display` to animate the live presentation; this game has no separate card/coin/ball motion channel. Reference dimensions above describe the neutral layout before v2 placement. See the [exact fields, transforms and limits](/game-skin-contract/). --- # Game skin contract v2 Source: https://docs.betworld.gg/game-skin-contract/ [Read as Markdown](/raw/game-skin-contract.md) · [JSON schema](/game-skin.schema.json) · [Per-game catalog](/game-skin-catalog.json) Build a custom game model from static GLB pieces and a versioned JSON skin. In **v2**, you can position, rotate and scale the body, each named physical control and the complete live display assembly. Add looping model animation, result-triggered clips and custom card, coin or Plinko motion. Betworld supplies game state, clickable actions and the final result. Use `game_skin_contract({"game":"blackjack"})` to get a v2 starter and the exact targets and motion channels for that game. Existing v1 skins continue to use their original fixed layout. The world document itself remains `version: 1`. Use the current `contract` hash from the per-game catalog for a new skin. `acceptedContracts` lists earlier compatible hashes too. Existing blackjack and baccarat skins retain the card and discard positions associated with their hash when the native tables are updated. To adopt a newer layout, download its reference model, adjust your model to its anchors, and update the hash. ## Manifest fields Every object is strict: use only the fields in its schema. All numbers must be finite. UTF-8 JSON must fit 65,536 bytes for v2, or 16,384 bytes for v1. | Field | Type and limit | Meaning | |---|---|---| | `version` | `2` | Skin format. `1` remains supported without the three v2 arrays. | | `id` | `^[a-z][a-z0-9_-]{0,47}$` | Unique skin ID within your world | | `game` | One of the thirteen game asset IDs | Must match all assigned entities | | `contract` | Current 16-character lowercase hex fingerprint | Reference geometry/version returned by MCP | | `body` | 64-character lowercase hex hash | Converted body asset from your library | | `bindings` | 0–32 entries; required | Replacement visual meshes | | `placements` | 0–34 entries; defaults to `[]` | Presentation layout changes | | `clips` | 0–16 entries; defaults to `[]` | Model/control/display animation | | `motions` | 0–4 entries; defaults to `[]` | Result-object motion overrides | A world may define up to 32 skins. Assign one with `"skin":"my-blackjack"` on an existing `kind:"game"` entity whose `asset` matches the skin. Entity position/yaw place the whole station; its entity scale stays `[1,1,1]` and floor Y stays 0. Props do not take skin references. To restore the native model, remove the entity's `skin` field. ## Mesh bindings Each binding has exactly two fields: ```json {"slot":"control.hit","asset":"HASH_RETURNED_BY_ASSET_UPLOAD"} ``` Use a `control.` from the selected game's `controls` catalog or a `part.` from its `parts`. Each slot may appear once. Omitted bindings retain their native visual; `bindings: []` is valid. Multiplayer Blackjack controls retain their original seat identity. Video Poker Hold controls retain their card index. Doubler and Crash expose no physical-button bindings because their buttons are regions of the live display. Upload the body and each distinct button/surface as separate static GLBs. One button hash can be reused across multiple slots. Uploaded names or extras do not select actions. Action/index/seat identity comes from the reference catalog, while the station comes from the assigned game entity. Bets use the currently authenticated player and the ordinary game endpoints. ## Coordinate system and fitting Positions use **station-local world units, Y up**, before the game entity's position/yaw. +Z faces the usual player side. Rotation uses **XYZ Euler radians**, with rotation matrix `Rx × Ry × Rz`. Scale is an axis multiplier. In Blender, game `[x,y,z]` becomes Blender `(x,-z,y)`. Convert rotations by conjugating the matrix with that axis conversion; do not merely swap Euler components. `bodyBounds` and each control's `bounds` already include the native source-to-world scale. `localBounds` is the native button mesh's geometry box. `matrixSource` is a column-major 4×4 source transform, with `sourceToWorldScale` supplied separately. Before placement, the complete body GLB is fitted to `bodyBounds`. Each bound button/surface is fitted to the native mesh's `localBounds` and parented to its trusted proxy. The fit is axis by axis: `scale = targetExtent / uploadedExtent`, followed by center alignment. A zero-extent axis uses scale 1. Match the reference width:height:depth to avoid unintended stretching. Export only the intended piece; stray geometry changes its bounds. ## Placements: moving controls and the live display Each placement has exactly `target`, `position`, `rotation` and `scale`: ```json { "target":"control.hit", "position":[0.6,0,0], "rotation":[0,0.15,0], "scale":[1.2,1,1.2] } ``` This offsets Hit by 0.6 world units along the station's X axis. `position` is an **offset from the reference pose**, not an absolute coordinate. Rotation and scale pivot around that control's reference `bounds` center. The body uses its own bounds center. The display pivots around the station origin. | Target | What moves | |---|---| | `body` | Your fitted body assembly | | `control.` | Native clickable proxy, custom/native visual and its raised label together | | `display` | Complete live presentation: screens, cards, grids, pegs, coin/result readouts, surface overlays and their generated click regions | `presentation.targets` from the catalog is the exact target list. Part bindings such as `part.playing_surface` move with `display`; they are not independent placement targets. Physical `control.*` targets are independent of `display`, so place them explicitly when redesigning a panel. Multiplayer Blackjack's three generated Bet/Settings panels move with its display, while its twelve physical hand controls use their own targets. A target may have one placement. Each position component is in **[-4,4]**, each rotation in **[-4π,4π]**, and each scale component in **[0.5,2]**. Defaults are identity when a target is omitted. Keep controls visible and within ordinary interaction reach. These transforms affect presentation and interaction proxies; station collision hulls and player/seat positions retain their reference shape. Build a shell that fits that walkable footprint. For the familiar table/player ratio, leave display Y offset at 0 and scale at 1. ## Clips: idle and result animation A clip has exactly `target`, `trigger`, `durationMs` and `keyframes`: ```json { "target":"body", "trigger":"result", "durationMs":900, "keyframes":[ {"time":0,"position":[0,0,0],"rotation":[0,0,0],"scale":[1,1,1]}, {"time":0.5,"position":[0,0.08,0],"rotation":[0,0,0],"scale":[1.02,1.02,1.02]}, {"time":1,"position":[0,0,0],"rotation":[0,0,0],"scale":[1,1,1]} ] } ``` `idle` loops after the station loads. `result` plays once when a new accepted result ID arrives; for shared games it uses the settled round ID. Clips do not place a bet. A result clip temporarily overrides the idle clip on the same target. Idle resumes afterward. Starting the next active/busy bet clears the preceding result clip. Duration must be an integer from **200 to 5,000 ms**. A clip contains **2–32 keyframes**. `time` is normalized 0–1, starts at 0, ends at 1 and increases strictly. Positions/rotations/scales have the placement bounds above. The first and last keyframe must be identity: position and rotation `[0,0,0]`, scale `[1,1,1]`. Between frames, components interpolate linearly. Angles are not shortest-path quaternion interpolation; provide intermediate angles for deliberate spins. Each `(target,trigger)` pair may occur once. Clip transforms are relative to the target's placement: the effective transform is `placement × animatedOffset`, both around the documented pivot. Result clips animate the assembly's presentation, not the values painted into it. ## Result motion: cards, coins and balls A motion has exactly `channel` and `keyframes`. Each frame has `time`, `progress`, `position` and `rotation`; it has no scale or duration. ```json { "channel":"coin_flip", "keyframes":[ {"time":0,"progress":0,"position":[0,0,0],"rotation":[0,0,0]}, {"time":0.45,"progress":0.3,"position":[0,0.6,0],"rotation":[0,0,1.4]}, {"time":0.8,"progress":0.85,"position":[0,0.2,0],"rotation":[0,0,0.5]}, {"time":1,"progress":1,"position":[0,0,0],"rotation":[0,0,0]} ] } ``` Time uses the game's existing presentation duration: `card_deal` 340 ms per card, `card_flip` 260 ms per reveal, `coin_flip` 2,800 ms, and `plinko_drop` 2,160 ms. Read `presentation.motionDurationsMs` from the current contract for these values. Native sequencing and any reveal pauses still apply. `progress` retimes the authoritative path, remains within 0–1 and never decreases. It must start at 0 and end at 1. Position is a path offset in station-local world units, each component **[-2,2]**. Rotation is an additional XYZ rotation, each component **[-8π,8π]**. Both endpoint positions and rotations must be zero. Frames have the same 2–32 count and strictly increasing 0–1 times as clips. A channel may occur once. | Game | Motion channels | Authoritative elements | |---|---|---| | Blackjack | `card_deal`, `card_flip` | Server hand ranks, deck/hand destination and dealer hole-card disclosure | | Multiplayer Blackjack | `card_deal`, `card_flip` | Same, shared across all three original seats | | Baccarat | `card_deal` | Player/Banker ranks and server-selected third cards | | Heads or Tails | `coin_flip` | Final Heads/Tails orientation and result readout | | Plinko | `plinko_drop` | Server path, risk and destination pocket | | Mines, Keno, Drago Tower, Dice, Limbo, Video Poker, Doubler, Crash | Use `display` clips | Live grid, number, cards, reel or graph stays linked to game state | `card_deal` interpolates between the native deck and each card's own destination using your progress, with your translation/rotation offsets replacing the standard deal arc. `card_flip` retimes the native reveal turn and adds offsets; the face changes at progress 0.5 using the already received rank. `coin_flip` retimes the native flip and adds your offsets; zero endpoint offsets restore the correct final side. `plinko_drop` interpolates along the server's peg path using your progress; your offset replaces the standard bounce arc. It ends at the server-selected bucket and releases the ball at the native completion time. These channels use the native result meshes. Your shell and physical controls can be custom meshes; individual card artwork, coin faces, grid symbols and text remain live platform elements. Display clips can move the full presentation for every game, including games without separate object-motion channels. The accepted target/channel vocabulary has no arbitrary node selector, property path, event handler, expression, script, shader, URL or account field. ## Complete starter Fetch the actual template and hashes before submitting; the strings below mark values to replace. ```json { "version":2, "id":"ivory-coinflip", "game":"coinflip", "contract":"CURRENT_16_HEX_FINGERPRINT", "body":"BODY_HASH_FROM_ASSET_UPLOAD", "bindings":[], "placements":[ {"target":"display","position":[0,0,0],"rotation":[0,0,0],"scale":[1,1,1]} ], "clips":[], "motions":[ {"channel":"coin_flip","keyframes":[ {"time":0,"progress":0,"position":[0,0,0],"rotation":[0,0,0]}, {"time":0.5,"progress":0.4,"position":[0,0.4,0],"rotation":[0,0,1]}, {"time":1,"progress":1,"position":[0,0,0],"rotation":[0,0,0]} ]} ] } ``` ## Modeling and preview Import the native model as reference, design your shell around the planned interface layout, and export only the new static body/button/surface pieces. Keep dynamic readouts visible. The JSON describes placement and animation separately from GLB geometry. Preview idle, active, disabled, occupied and settled states in the browser. Check all split hands and shared seats, maximum Mines grids, Drago difficulties, Poker holds, Dice slider extremes, Plinko drops and both coin sides. Controls carry their native disabled/hover feedback, labels and click identity when moved. The layout still needs enough room for players to see and reach them. ## Exact MCP sequence 1. `world_download({})` returns the token's world, current `revision`, document, asset library and native source URLs. 2. `game_skin_contract({"game":"blackjack"})` returns the current contract fingerprint, body box, ordered controls, optional parts, runtime mounts, strict schema, limits and starter manifest. Use the selected game's response, not a guessed action list. 3. Upload the body with `asset_upload({"name":"Ivory blackjack body","glbBase64":"..."})`. The decoded input must be at most 4,000,000 bytes. Record the returned `hash`; do not hash your original file and guess the remote identifier. 4. Upload each distinct custom button/surface the same way. All are static GLBs, processed through the same converter as props. They are library assets, not ordinary prop placements. 5. Create the manifest and call `game_skin_save({"revision":CURRENT,"skin":MANIFEST,"entityIds":["blackjack:0"]})`. 6. Store the returned `revision` and `budget`. Download the draft again when another writer has changed it; never blindly increment a stale revision or overwrite the other writer's work. 7. Review the new appearance, then publish using the signed-in owner's normal site control. MCP credentials cannot publish or access a wallet. `entityIds` is required and contains 0–64 unique existing IDs. An empty list saves the definition without assigning new stations. A nonempty list assigns the skin only to those matching game entities. Saving an existing skin ID replaces that definition; all entities already referring to that ID see the new draft definition. Existing references to a different game make the save fail rather than silently changing game type. `world_upload` and authenticated draft PUT accept the same `skins` definitions and entity references, with identical server validation. `world_edit_entities` can add/remove an entity's `skin` field while preserving definitions already in the document. None of these operations publishes. No separate skin database or mutable asset alias is involved: the manifest is part of the revisioned world document, and the asset hashes are immutable. ## Blender bridge Install the current trusted [Betworld bridge](/downloads/betworld_blender.py), connect your private world credential and download the world. Existing skins are included in scene metadata. The bridge previews custom bodies, socket meshes and v2 placements, including native display parts and moved button labels. Review clips, result motion, live cards and state-dependent labels in the browser. Select only the static meshes of one skin asset and choose **Upload selected skin mesh**. This exports a GLB with animation, skinning, extras, cameras and lights disabled, uploads it, and stores the returned bare hash in `scene["betworld_last_skin_asset"]`. It does **not** create a separate prop entity. Repeat for distinct button/surface assets. Put the manifest JSON into a Blender Text datablock named `betworld-skin.json`. Select the existing game **anchor objects**, then choose **Save skin JSON to selected stations**. The bridge calls `game_skin_save` with the scene's current revision, updates that revision and preserves the definition for later world uploads. Download again into a new scene to preview the applied skin. Existing scenes are preserved. For an AI using the bridge module, the same helpers are `upload_skin_mesh(bpy.context)` and `save_game_skin(bpy.context, skin_dict, entity_ids)`. Run these helpers in your local Blender scene to transfer the exported GLB and manifest. ## Contract compatibility Fetch the current contract before modeling or updating a skin. Its fingerprint identifies the game's socket geometry and runtime mounts. If a save reports an incompatible fingerprint, fetch `game_skin_contract` again, compare the measurements and update your manifest and artwork to match. ## Ownership, storage and resource limits An asset hash identifies bytes after canonical conversion and is scoped to the owner. The server computes SHA-256 over owner identity plus canonical bytes. The same original upload by another owner does not grant reuse rights to their library entry. Every body and binding hash, including unused skin definitions, must exist in the authenticated creator's library. Save and publish both enforce ownership and budget admission. Every input and converted model must fit the 4,000,000-byte service limit. Textures must be embedded static PNG/JPEG/WebP, each at most 2048×2048, with an aggregate decoded budget of 4,194,304 pixels per asset. Mesh/node/accessor limits and conversion time limits apply in addition to bytes. See [asset limits](/assets/) for details. All converted models count against the creator's 100,000,000-byte library. Distinct used skin hashes count once toward the world's 100,000,000-byte download limit and decoded texture budget, even if the same hash is also used as a prop. Each placed body and binding adds rendered triangles and a conservative mesh-instance memory allowance. A placed v2 skin also reserves 32,768 bytes, plus 4,096 bytes per clip/motion and 2,048 bytes per placement for presentation state. Reusing the same button in ten sockets is ten geometry placements. Native game overhead remains in the estimate because the platform still loads native interfaces and collision shapes. The existing world limits still apply: 1,000,000 entities, 500,000,000 estimated resident bytes, 20,000,000 placed triangles and 32,000,000 texture pixels. Check all returned budget values after saving. The base download allowance now reserves 25 MB for the shared native assets; custom downloads are additional. Unused skin definitions are validated for ownership but are not downloaded to a joining player's client. ## Supported fields and materials Use the manifest fields in this guide and the exact slot IDs returned by the catalog. Betworld supplies each slot's action, live state, labels and authoritative result. Your v2 JSON supplies presentation transforms and numeric animation keyframes. Model names and metadata are removed during conversion; assign controls through `bindings`. Skin uploads use static GLB meshes with embedded images and supported glTF materials. Export static geometry without cameras, lights, rigs, morph targets or GLB animation tracks. Put skin animation keyframes in the JSON manifest. For troubleshooting rejected files, follow [Custom assets](/assets/). --- # Games, movement and appearance Source: https://docs.betworld.gg/games/ ## Supported game stations The live catalog includes Blackjack, Multiplayer Blackjack, Baccarat, Drago Tower, Mines, Keno, Dice, Coinflip, Plinko, Limbo, Video Poker, Doubler (`roulette`) and Crash, plus any additional station types returned by the deployed catalog. Use `/catalog.json` and `world_download` rather than inventing names or IDs. Each supported station has a fixed maximum count and ID range. A game object must retain its default proportions, unit entity scale. Moving (including elevation 0–64) and rotating a station is supported. Keep a supporting floor at the station origin. Table felt tint is supported on relevant models. [Game skins](/game-skin-contract/) can replace the body and named button/surface meshes while preserving the trusted gameplay actions; v2 supports movable presentation and result motion. The [custom game-model guides](/betting-models/) cover each of these 13 creator game types individually: their physical controls, live screens, card/coin/ball animation clearance, proportions, placement and a copyable AI modeling brief. Use the [measured geometry reference](/model-reference/) to locate current native controls rather than guessing from a concept image. A game elsewhere on the website is not automatically placeable; the creator catalog is the authority. You cannot upload replacement betting logic, change odds, change card-control behavior, add arbitrary game types or alter settlement behavior through a world. Custom props are scenery; they do not become betting stations by looking like a table. ## Multiplayer Blackjack Use `blackjack_group:0` or `blackjack_group:1`. The runtime creates the seats and their viewing positions from the shared table layout. Do not create shared-seat IDs manually or rescale the table. ## Movement and FOV Movement, jumping, collision behavior and supported camera settings are managed by the Betworld client. A world document cannot set player speed, gravity, FOV, input bindings, camera scripts or network behavior. Players can use the settings offered by their own client. Design for the existing character proportions and interaction reach. Leave clear paths around each table and enough room for other players. Building at the schema bounds is not a substitute for a walk-through. ## Guest lobby The public meadow lobby loads on the home page, including for signed-out visitors. Guests can move and be seen by others but cannot chat, bet or use creator tools. A signed-in player joins a published world from the browser or active-world board. The public lobby and its backdrop are platform-maintained. A creator token does not grant permission to modify them or another creator's world. --- # Build in the game Source: https://docs.betworld.gg/in-game-editor/ ## Open your world builder Sign in, open **Create your world**, name your world and select **Create world**. The builder opens with your starting room and native game stations. For an existing world, select it in **Your worlds** and choose **Open world builder**. While playing in a world you own, open the Escape menu and choose **Edit this world**. The builder loads your latest saved draft into a private 3D workspace. Other players continue using the published layout. Your player leaves the live room while you edit. Game controls and betting are unavailable in the builder. Only the owner can read, save or publish the draft through this interface. ## Place objects The asset library is on the right: - **Build:** floor slabs, walls, doorways, window walls, stairs and ramps. - **Props:** building blocks, pillars, carpets, benches, planters and bar counters. - **Games:** native betting stations, with the placed count and available capacity shown on each card. - **Uploads:** your validated custom GLB models. - **Objects:** search the objects already in your world. Select one to focus the camera and open its position, rotation and size controls. - **World:** terrain generation, backgrounds, surface colors, storage, saved budget and draft controls. Each card shows a preview of the actual model, including your uploads. Select an asset, move your pointer onto a floor or prop surface and click to place it. On a phone or tablet, select the asset and tap the surface. A transparent model previews the placement. Press **R** or choose **Rotate** in the placement prompt to turn it by 45 degrees. Press **Escape**, choose **Select**, or use the cancel button to cancel placement. Set **Build area** above the viewport to enlarge the placement grid and playable floor. Choose 56, 96, 128, 192, 256, 320 or 384 metres per side; **World → Build area width (m)** accepts any whole number from 56 to 384. Your existing objects keep their positions. Resizing supports undo; shrinking is refused if an object would fall outside the new bounds or block the relocated entrance. Object origins must stay within ±half the build width on X/Z and 0–64 metres on Y. The gold area at the entrance is reserved: keep origins with `abs(x) < 3` and `z > buildSize / 2 - 6` clear. Keep walking routes and game controls accessible when arranging larger objects. The editor does not automatically prevent every overlap between props. Uploaded props are centered horizontally, grounded and normalized so their longest dimension is one game unit before the entity scale is applied. Set the scale in the inspector after placement to choose the visible size. ## Build floors and structures Open **Build** for the modular building kit. The pieces have matte stone surfaces and can be tinted. Every piece is one entity and uses instanced rendering after saving. | Piece | Default width × height × depth | Collision | | --- | --- | --- | | Floor slab | 6 × 0.25 × 6 m | Solid slab | | Wall | 6 × 6 × 0.3 m | Solid wall | | Doorway | 6 × 6 × 0.3 m | Open center, 3 m wide and 4.8 m high | | Window wall | 6 × 6 × 0.3 m | Open window, 3 m wide, from Y 2.2 to 4.8 | | Stairs | 4 × 6 × 12 m | Smooth walking slope beneath the visible steps | | Ramp | 4 × 3 × 8 m | Sloping surface | Use **Width**, **Height** and **Depth** in the inspector to enter dimensions in metres, measured along the object's own axes. The underlying scale remains 0.1–12 times its source dimensions. The doorway opening and stair slope scale with the piece; keep enough headroom and a gentle enough slope for players. Use **Copy beside → Left / Right / Back / Front** to create an adjacent copy aligned to the selected piece's dimensions and rotation. The new copy becomes selected; repeat to extend a wall or floor. Undo removes each copy separately. Enable **Keep placing** to place the same prop repeatedly without returning to the library. **Shift-click** repeats one placement on desktop. Rotation, dimensions and tint carry over; each placement is undoable. Press **Escape** to finish. This feature applies to props; games retain their available station counts. Build enterable structures from separate walls, floors, doorways and stairs. Uploaded props and the original scenery pieces still use one solid bounding box per entity; a single uploaded building shell would block its own interior. Export its modular components separately when using Blender. - **Place on → Surfaces** places the new object's bottom onto a visible, upward-facing prop surface. This works on saved floors and freshly added pieces. Grid snapping aligns X/Z; the surface determines the precise elevation. - **Place on → Height grid** places objects on the horizontal plane selected by **Grid height (m)**. Set this to the elevation of the next floor when you want to build above empty space. - Use the **Move** tool's vertical handle or the inspector's **Y** field to adjust elevation after placement. This works for props and game stations. **Set grid to top** in the inspector moves the working grid to the selected prop's top surface. This changes only the editing view. The placement grid can be raised from 0 to 64 metres. In Surfaces mode, it is the fallback plane and minimum eligible surface height. Return it to 0 to place objects on lower floors. Put floors beneath elevated game stations and leave enough standing space around their controls. The native stairs climb toward local negative Z; rotate the piece to choose the approach. Their default rise is 6 m. For two floors with origins at Y = 0 and Y = 6, place the stairs on the lower slab's top at Y = 0.25 so the landing meets the upper slab's top at Y = 6.25. Leave an opening in the upper floor above the stair flight. The room ceiling rises to accommodate elevated entities; choose **World → Layout → Outdoor** for freestanding buildings. Game stations retain unit scale. Their controls, cards, displays and player approach points move with the station, keeping table height relative to the floor unchanged. A moved floor does not carry other entities with it: select and move its contents separately. ### Furnish below a roof Enable **Cutaway**, then set **Show below (m)** to the height you want to see. Geometry above that plane is hidden and cannot intercept selection or surface placement. This lets you place furniture beneath an existing upper floor or roof. For a room under a floor at Y = 6, a cutaway height of 4.5 m exposes the interior. The clipped view is editor-only; saving and publishing keep every object intact. Turn Cutaway off to inspect the complete building. Changing **Grid height** sets the suggested cutaway height to six metres above it. You can adjust **Show below** independently. Asset thumbnails always show the complete model. ## Move, rotate and resize Click or tap an existing object to select it. The highlighted bounds and transform handles identify your selection. | Tool | Shortcut | Operation | | --- | --- | --- | | Move | W | Drag an axis or plane handle to reposition the selection. | | Rotate | E | Drag the vertical rotation ring. | | Resize | Q | Change a prop's width, height or depth. | | Turn 45° | R | Rotate the selected object or placement preview. | | Focus | F | Move the camera close to the selected object. | | Duplicate | Ctrl/Command + D | Create a copy, then choose its surface or grid position. | | Delete | Delete / Backspace | Remove the selected object. | | Undo | Ctrl/Command + Z | Undo the latest edit. | | Redo | Ctrl/Command + Shift + Z | Reapply an undone edit. | | Save draft | Ctrl/Command + S | Save your current document. | The inspector also accepts numeric position, rotation and scale values. Commit a number by pressing Enter or leaving the field. Rotation is displayed in degrees; the saved world document uses radians. Prop dimensions on each axis can range from 0.1 to 12 times the source size. Use **Tint** to recolor a prop. Game stations retain unit scale and can move vertically onto another floor, keeping tables, players and native interactions in proportion. The **Snap** selector supports 0.25, 0.5, 1 and 2 game units, or Off. When snapping is enabled, rotation handles snap to 15 degrees and scale handles to 0.1 increments. Undo keeps up to 100 editing operations in the current session. Saving retains the undo history until you leave or reload the builder. ## Move the camera On desktop, drag empty space to orbit, right-drag to pan, and scroll to zoom. On touch devices, use one finger to orbit and two fingers to pan or zoom. **Top view** looks down at the layout; **Show whole world** resets the overview. The **Assets** button opens or closes the right panel, including on mobile. Select **Fly camera** (the navigation arrow) to move freely through your build. Use **WASD** to move, **Q** to descend, **E** to rise, and **Shift** to move faster. Hold the right mouse button and drag to look around. Click an object to keep editing from your new viewpoint. On touch devices, drag to look and hold the Forward, Back, Left, Right, Up or Down buttons to move. **Escape** returns to orbit controls. Flying changes only your camera; it does not move your spawn or any entities. The W/E/Q transform shortcuts resume when you leave Fly camera mode. The builder uses a cutaway view: the room walls and ceiling are hidden so you can see the layout from above. They are present when playing the world. Change their color in **World**. The grid, selection outlines, entrance marker and transform handles appear only in the builder. ## Upload your own models Choose **Upload** and select a `.glb` file: 1. Export a static model with its textures embedded in the file. 2. Keep the file at or below **4,000,000 bytes**. Each embedded texture must be at most **2048 pixels** on either axis. 3. Upload it and wait for validation. The server converts it through the existing isolated prop processor. 4. Select the accepted model under **Uploads** and place it in your world. The viewport loads only the accepted server output. Rejected files are not added to the library or rendered as a local preview. Your library can contain up to **100 MB** of converted models and background images, shared across your worlds. Uploading adds a library asset; placing it adds an entity to the draft. Deleting a placed entity keeps its reusable library asset. Use [custom models](/custom-models/) for detailed export requirements. The asset uploader creates static scenery. To replace a betting machine's body or controls, use the [game skin contract](/game-skin-contract/) through Blender or MCP. Existing skin definitions, bindings and numeric animation data are preserved when the builder saves your world; moving a station moves its configured presentation with it. ## Terrain and backgrounds In **World**, set **Layout → Outdoor**. Choose a terrain preset, set its size (128–512 m), height, roughness and seed, or select **Flat**. **New seed** regenerates the surrounding hills; **View terrain** frames the landscape. The central build area remains flat, and the surrounding terrain is walkable. Terrain width must be at least the build width plus 64 metres; enlarging the build area automatically expands terrain when necessary. For the background, choose **Sky**, **Lobby panorama**, or **Upload panorama**. Upload a PNG, JPEG or WebP up to 12 MB, 8192 pixels wide and 16 megapixels, with an aspect ratio of 2:1 to 8:1. Set its rotation to align the horizon. Both terrain and background settings support undo and are saved with the draft. See [terrain and backgrounds](/terrain-backgrounds/) for image preparation, exact parameters and the upload API. ## Save a private draft **Save draft** persists your complete layout without changing the playable world. The header shows whether you have unsaved changes and the current saved revision. Leaving with unsaved changes offers **Save & leave**, **Discard & leave**, or **Keep editing**. Uploads already accepted by the server remain in your asset library even if you discard layout edits. Every save checks asset ownership, station IDs, placement bounds and the world budgets: up to 1,000,000 entities, 500 MB estimated runtime memory and 100 MB total download, with the first reached limit applying. See [limits](/limits/) for the additional geometry, texture and manifest caps. The **World** tab shows budget totals returned by the last successful save. If another browser, Blender or your AI saves first, the revision check rejects your stale save. Use **Download my changes** to keep a JSON copy, then **Reload latest** to load the current saved draft. Reloading discards your unsaved local edits. There is no automatic merge; you can reapply your changes in the builder or ask your AI to merge the downloaded document with the latest revision. ## Publish a live update Choose **Publish** to save any pending edits and queue that exact revision. At least one game station must remain in the layout. Players see **Update incoming** at the top of the game. New wagers in that world are blocked on the server. Existing hands, picks, draws, cash-outs and shared rounds continue normally. Waiting player-versus-player coinflips can be cancelled by their creator or expire under the existing ten-minute rule; matched flips continue to settlement. After a notice period of at least five seconds, the server applies the queued snapshot as soon as all accepted bets have settled. Players automatically download the updated world and assets. Only the 3D world reloads; the site shell stays mounted. Other worlds remain open for betting. Further draft edits do not change the queued snapshot. In the **World** tab, choose **Cancel pending update** to reopen betting without applying it. You can then save and publish a different revision. Pending updates are stored in the database and survive a server restart. The server does not force a payout or erase an unfinished game to hurry publication. Choose **Play world** to enter the published layout. For new worlds, this becomes available after the first publication completes. Your draft remains private until publication. ## Combine the editor with AI and Blender The builder and MCP use the same document, asset library and revision numbers. For example, arrange native tables in the builder, save, ask an AI to build a custom prop in Blender and upload it, then reload the builder and place it from **Uploads**. Coordinate saves so only one client edits the draft at a time. The builder uses owner-session routes in the [World HTTP API](/world-api/): `GET /:id/draft`, `PUT /:id/draft`, `POST /assets`, `POST /backgrounds`, `POST /:id/publish`, `DELETE /:id/publish` and `GET /:id/update`. An AI world credential can edit drafts and upload models; publishing uses your signed-in owner session. ## Editing official maps as an admin Sign in to the admin panel with your password and authenticator. In **Lobby** or **Pyramids**, press **Escape → 3D editor**. You can move game stations in Pyramids, place props, and reposition the leaderboard TVs and portals. The lobby stays free of betting stations. Click either wooden world portal in the lobby to move or rotate it. Its frame, sign, portal surface and walk-through trigger move together. Pyramids' placed scenery is editable too: columns, walls, canopies, sofas, rugs, palms, braziers, pyramids, paving and terrain tiles. Related pieces move together—for example, a sofa includes its cushions. Use **Objects** to search for pieces obscured by a canopy or other scenery, then choose **Focus** or use the fly camera to inspect them. The sky panorama and ambient sand particles remain background effects. Original map scenery retains its authored materials and can be positioned within ±2,048 metres on each axis, including below ground. Newly placed library props and games use the normal build-area limits. The original scenery assets are available only in their own official map. Save a draft, then select **Publish**. Players see the update notice; new bets pause until existing games finish, then the world reloads. Saved official layouts survive server restarts. Leaderboard TVs show richest-online, profit and wager rankings, with Online, All time and This month views. A Lobby portal returns players to the main lobby by walking through it or selecting it. Each world supports up to four of each fixture. --- # Build your world Source: https://docs.betworld.gg/ Betworld worlds are shared 3D spaces built by their owners. Use the **in-game world builder** to place, move and rotate props and game stations, upload your own models, save a private draft and publish your layout. You can also connect an AI assistant through **MCP** and design in Blender. Both workflows use the same world document, asset library and saved revisions. ## Start here - **[Quickstart](/quickstart/)** — create and publish your first world. - **[In-game world builder](/in-game-editor/)** — placement, transforms, manual uploads, saving and live updates. - **[Connect MCP](/connect-mcp/)** — endpoint, credentials and client compatibility. - **[Blender workflow](/blender/)** — download, build, export and upload. - **[Custom betting-machine models](/betting-models/)** — safe static artwork, required controls and current support. - **[Complete modeling workflow](/model-authoring-workflow/)** — detailed Blender setup, clearances, materials, normalization, alignment and upload steps. - **[Measured model reference](/model-reference/)** — current native button bounds, runtime mounts and a Blender clearance-guide example. - **[Agent instructions](/agent-guide/)** — a practical checklist for autonomous world builders. - **[Limits and performance](/limits/)** — 1,000,000 entities, 500 MB estimated memory and 100 MB total download, whichever constraint is reached first. - **[World HTTP API](/world-api/)** — every route, authentication method, request body, response and error. ## Give these docs to your AI Send your assistant this URL: **https://docs.betworld.gg/llms-full.txt**. The [documentation index](/llms.txt), [complete text](/llms-full.txt), [world schema](/world.schema.json), [catalog](/catalog.json) and [limits](/limits.json) are public. Every guide also has a raw Markdown copy under `/raw/`. No sign-in, JavaScript execution or captcha is required to read them. Documentation never includes your private credential. Create one in Betworld and pass it through your client's secret settings. ## What you can customize Arrange the supported betting stations, build scenery from built-in blocks or your own GLB props, and choose the floor, wall and prop colors. Betting stations keep their standard dimensions, interaction logic and odds. Game bodies and named physical button meshes can be replaced through [game skin contract v2](/game-skin-contract/). Use v2 placements and numeric clips/motions to customize controls and result presentation. Actions and game state are supplied by Betworld. Players download the published world and its assets with a loading-progress screen before entering. The meadow lobby's active-world board and the world browser let players discover published worlds. ## Creator earnings Owners earn **10% of user edge (the theoretical house edge)** on settled wagers in their world. This is not 10% of the wager or of a player's actual loss. A $100 wager on a game with a 1% theoretical edge earns the owner $0.10. Earnings are credited in $0.0001 increments; smaller fractions carry forward. See [publishing and earnings](/publishing/). --- # Limits and performance Source: https://docs.betworld.gg/limits/ Your world must fit every applicable budget. Decimal MB means 1,000,000 bytes. | Limit | Maximum | |---|---:| | Placed entities | 1,000,000 | | Estimated runtime memory | 500 MB | | Total world download | 100 MB | | JSON save request, including the world manifest | 64 MB | | Creator uploaded asset library | 100 MB | | Files in your model and panorama library | 512 | | Prop upload attempts | 60 per rolling hour | | Panorama upload attempts | 12 per rolling hour | | Draft save attempts | 300 per hour, up to 512 MB of submitted documents | | MCP JSON request | 20 MB; use the HTTP draft route for larger documents | | Individual GLB, before and after conversion | 4 MB | | Placed triangles, including repeated instances | 20,000,000 | | Decoded texture pixels per world | 32,000,000 | | Prop render batches | 2,000 | | Players in one world | 50 | | Worlds per creator | 3 | | Upserts / removals in one MCP edit | 1,000 each | ## Read the budget after saving Draft saves return a `budget` object. Track `entities`, `bytes` and `memoryBytes` as your AI builds. `bytes` counts the manifest, a standard-asset allowance and each distinct uploaded GLB once. `memoryBytes` estimates runtime cost from entities, instance data, collision data, decoded geometry and textures. Your device's actual memory use varies. Repeated placements reuse an asset's download, geometry and textures. Each placement still adds entity data, instance memory and rendered triangles. A world can reach its memory or download budget before its entity limit. Prop batches group copies of the same asset within an 8 × 7 × 8 spatial cell. Each mesh/material part adds a batch. Check `budget.propBatches` after saving; spread-out, multi-material models can reach this limit before the triangle budget. Upload attempts include failed conversions. Browser, HTTP and MCP uploads share your creator allowance. Send original bytes without HTTP `Content-Encoding`. Finish sending each request within 30 seconds. When the API returns `429`, respect `retryAt` or `Retry-After`; do not retry in a loop. A `503` means processing or storage capacity is temporarily unavailable. Asset downloads also share per-client and server byte/concurrency budgets. Keep immutable asset URLs cached and use their `ETag` for conditional requests. See the [World HTTP API](/world-api/) for save responses and [world format](/world-format/) for document fields. Current values are also available as [limits.json](/limits.json). ## Build for phones as well as desktop - Reuse GLBs for repeated furniture, trees and architectural pieces. - Use a few broad meshes for floors and walls, and keep material counts small. - Combine related textures into compact atlases. - Keep walkways clear and avoid layers of overlapping geometry. - Preview your world on your target devices as you build. Props render in spatial groups with shared geometry and materials. Their collision follows oriented bounding boxes; split an arch into separate solid pieces when players need to walk through it. ## Loading and empty worlds Players download your published document and assets with a progress screen before joining. Cached assets can speed up return visits. Switching worlds releases the previous 3D scene's rendering resources. Empty worlds remain saved and discoverable. Their full scenes and transient room state are unloaded when nobody is playing. Your AI can still download and edit a saved draft. Accepted bets finish settling even if their players leave. ## Terrain and panoramas Generated terrain is 128–512 units wide with a fixed 192 × 192 grid. A panorama accepts up to 12 MB input and 8 MB canonical WebP output, up to 8192 × 4096 dimensions within a 16,777,216-pixel cap. Models and converted images share the 100 MB library quota. Referenced backgrounds count toward world download, texture and memory limits; generated terrain counts toward geometry and memory. See [terrain and backgrounds](/terrain-backgrounds/) for the complete contract. --- # MCP tool reference Source: https://docs.betworld.gg/mcp-tools/ All tools operate on the world selected by your credential and its owner's asset library. Tool success includes `structuredContent` plus equivalent JSON text. Tool failure uses `isError: true`; inspect the returned message even when HTTP itself succeeded. ## world_download Input: `{}`. Returns `worldId`, `name`, `revision`, `document`, `assets`, `sources`, `gameScale`, `catalog`, `limits` and `schema`. Asset entries include owner-scoped hash, name, size, triangles, pixels, mesh-part count and a public immutable GLB URL. Source URLs identify the platform's prop, game and shell templates. This reads your editable draft, which can differ from the published version. Batch related changes to keep downloads efficient. ## world_upload Replaces the full draft. It does not publish. ```json { "revision": 1, "document": { "version": 1, "floor": "#dad4c4", "walls": "#e8e1cf", "entities": [ {"id":"dice:0","kind":"game","asset":"dice","position":[-8,0,4],"yaw":0,"scale":[1,1,1],"color":"#d7ba7f"}, {"id":"pillar-west","kind":"prop","asset":"pillar","position":[-14,0,-10],"yaw":0,"scale":[1,3,1],"color":"#ddd6c4"} ] } } ``` The result contains `revision` and `budget`, including `entities`, `bytes`, `manifestBytes`, `memoryBytes`, `triangles` and `pixels`. The submitted revision must exactly match the current draft. Validation includes owner asset membership, game identity, transforms, duplicate IDs and budgets. ## world_edit_entities Adds or replaces entities by ID and removes selected IDs in one revision: ```json { "revision": 2, "upsert": [ {"id":"bench-east","kind":"prop","asset":"bench","position":[14,0,8],"yaw":1.5707963267948966,"scale":[1,1,1],"color":"#42756b"} ], "remove": ["pillar-west"] } ``` Both arrays are optional and default to empty. Each permits at most 1,000 entries. Removal happens first; an upsert with the same ID then recreates it. Unmentioned entities and room colors are preserved. The entire resulting world must pass validation. This avoids a huge upload request, but validation and database serialization still process the complete draft; batch related changes together. ## asset_upload ```json {"name":"Ivory planter","glbBase64":"BASE64_OF_A_SELF_CONTAINED_GLB"} ``` The decoded GLB must be at most 4,000,000 bytes; the encoded JSON is larger. Returns `hash`, `name`, `size`, `triangles`, `pixels` and `meshes`. Reference it as `upload:` in a prop entity. The content hash is owner-scoped. Uploads are validated and re-encoded; the returned bytes can differ from the source file. ## asset_download ```json {"hash":"64_lowercase_hexadecimal_characters"} ``` Returns the library entry and its GLB URL. The hash must belong to the credential's owner. Download the URL as binary GLB data. ## REST transfer alternatives The official bridge uses MCP. Tools that need a binary transfer can also use the following Bearer-authenticated endpoints on `https://betworld.gg`: | Method | Path | Purpose | |---|---|---| | GET | `/api/worlds/ai/export/world` | Full draft and source metadata | | GET | `/api/worlds/ai/draft/document` | Draft, catalog and schema | | PUT | `/api/worlds/ai/draft/document` | Save `{revision,document}` | | POST | `/api/worlds/ai/assets/upload` | Raw GLB with `Content-Type: model/gltf-binary` and `X-Model-Name` | Use `Authorization: Bearer …`. Native clients can omit `Origin`; if supplied, it must match the Betworld origin. See the [complete HTTP API](/world-api/) for owner routes, publishing, credentials, request limits and error responses. ## Rate and concurrency limits World service calls are limited to 120 requests per minute per client IP. Heavy draft writes and reads have bounded admission slots; a busy server returns 503 with `Retry-After`. Retry transient errors with backoff and jitter. Do not flood retries or parallelize revisions for the same world. Public GLB downloads use a separate higher read limit. ## `game_skin_contract` Input: exactly `{"game":"blackjack"}`; `game` must be a supported asset ID. Read-only. Returns the game's fingerprint, `bodyBounds`, `sourceToWorldScale`, ordered `controls`, optional `parts`, `runtimeMounts`, `presentation` (targets, motion channels, triggers and units), v2 starter `template`, strict manifest `schema`, limits and documentation URL. The starter body is an all-zero placeholder, not an uploaded asset. Replace it before saving. The ordered control catalog describes action/index/seat mappings owned by Betworld. Upload only the slot ID and an asset hash. Doubler/Crash return no physical button slots because their controls are live display regions. ## `game_skin_save` ```json { "revision": 12, "skin": { "version": 2, "id": "ivory-blackjack", "game": "blackjack", "contract": "REPLACE_WITH_CURRENT_FINGERPRINT", "body": "REPLACE_WITH_CONVERTED_BODY_HASH", "bindings": [], "placements": [], "clips": [], "motions": [] }, "entityIds": ["blackjack:0"] } ``` Use real values from `game_skin_contract` and `asset_upload`; placeholders above are not valid hashes. Input fields are exactly `revision`, `skin`, `entityIds`. The entity array contains 0–64 unique existing matching game IDs. An empty array saves an unassigned definition. Saving a matching definition ID updates that draft definition; existing entity references remain attached. The response is `{revision,budget}`. A revision conflict requires downloading and reconciling the latest draft. Validation rejects wrong-game assignments, missing IDs, unknown/duplicate slots, foreign assets, stale fingerprints, arbitrary action arguments, callbacks and extra fields. Existing references to a replaced definition must still match its game. The saved definition belongs to your connected draft. Publish the finished revision from your world panel. Read [the complete contract](/game-skin-contract/) for every accepted field, fitting rule and resource limit. `world_upload` may carry the same definitions, and `world_edit_entities` preserves the existing `skins` array while editing references. ## `background_upload` Pass `{name, imageBase64}` to upload a PNG, JPEG or WebP panorama. Maximum decoded input: 12,000,000 bytes; width 512–8192; height 256–4096; aspect 2:1 to 8:1; maximum 16,777,216 pixels. The result contains `{hash, name, size, width, height, pixels}`. Use the hash in `document.background` with `mode: "image"` and a numeric `yaw`, then save through `world_upload`. Terrain parameters use `document.terrain`. See [terrain and backgrounds](/terrain-backgrounds/). --- # End-to-end game model workflow Source: https://docs.betworld.gg/model-authoring-workflow/ [Read as Markdown](/raw/model-authoring-workflow.md) · [Exact contract](/game-skin-contract/) · [Per-game guides](/betting-models/) ## 1. Download the current world and contract Connect an AI client to Betworld MCP with the credential for the intended world. `world_download({})` returns the current draft revision, document, owned assets and native model source URLs. The credential is world-scoped and cannot publish, bet or access balances. Keep it out of Blender custom properties, saved Text blocks and exported files. Call `game_skin_contract({"game":"baccarat"})` for each game being designed. Store the returned fingerprint and the exact socket list. Read the corresponding game guide, `/model-proportions.json`, `/betting-interfaces.json` and `/game-model-reference.json`. Do not take measurements from an image or use another game's controls. The two MCP services have different roles: local Blender MCP can run your AI's modeling operations on your own workstation; Betworld MCP accepts converted assets and strict world JSON. Python used locally to construct a model is never uploaded as world behavior. ## 2. Create a locked reference assembly Download the world through the current Betworld Blender bridge. It creates a new scene without deleting existing scenes. Existing skin definitions and entity references round-trip with the scene. The bridge imports the native source library with the proper source scale; do not apply that scale again. Keep the game at unit entity scale. Set its anchor Y to the supporting floor elevation (0–64 world units). Use the player's canonical body and eye-height reference. The Baccarat playing plane must remain at 0.48273607884945505 of canonical bare body height, approximately 1.376896 world units above the floor. Blackjack and shared Blackjack have their own precisely documented playing planes. Game entity scale remains `[1,1,1]`. Make wireframe guides for body bounds, every physical button and the live screen/grid area. The catalog's bounds are world-space measurements; the native control's local geometry and `matrixSource` define its local fitting orientation. Keep native meshes locked as reference, not included in your export. ## 3. Model the replacement body Create a cabinet or table shell matching the contract's body-box aspect ratio. The runtime fits the uploaded model's whole bounds to that fixed box. If the width:height:depth ratio is wrong, the artwork will stretch. An accidentally exported object far from the machine changes those bounds and can shrink the intended model. Leave openings for the platform interface. The client retains its interactive top, labels, buttons, live screen, grids, cards, coins and other dynamic pieces. Do not sculpt a solid panel across a live display, or cover the control bank with a new rail. Preserve all seat approaches and the original collider envelope. Custom holes in visual geometry do not remove native collisions. For reusable button shapes, model one compact static mesh per distinct design. It will be fitted to a named native control's mesh-local box. Do not bake a second button label into the mesh. The platform retains the native label and hit proxy. Bind the same asset hash to multiple sockets when appropriate. If a game exposes `part.playing_surface`, its static surface can be replaced while card mounts and game-state rendering remain unchanged. Body textures may include thematic art. They must not impersonate a balance, result, payout, success indicator or live betting control. V1 preserves protected game visuals; static artwork can still be misleading and needs visual review. ## 4. Export and upload assets Select only the meshes for one asset and choose **Upload selected skin mesh**. The bridge exports embedded GLB, disables animation, skinning, extras, cameras and lights, and calls `asset_upload`. The returned owner-scoped canonical hash is stored as `scene["betworld_last_skin_asset"]`. No ordinary prop entity is added. Alternatively, export a self-contained GLB and call `asset_upload` from your AI client with its base64 bytes. Export each body, button design and optional surface separately. Do not upload `.blend`, a Python script, a ZIP archive, linked textures or a JavaScript package. Each input and converted result must fit 4,000,000 bytes. Embedded texture dimensions and aggregate decoded pixels have independent limits; a small compressed file can still be rejected. Record the returned hash, byte size, triangles, texture pixels and mesh count. Never guess the canonical hash from the source file. Conversion rewrites bytes and removes metadata. Changing the local artwork requires a new upload and replacing the relevant hash in the manifest. ## 5. Build the strict skin manifest Use the starter from `game_skin_contract`. Set a unique skin `id`, replace the body placeholder with your uploaded hash, and add any desired bindings. Each binding contains only a listed `slot` and an owned `asset` hash. Omitted sockets retain native meshes. For example, a Baccarat choice control is selected by `control.choice_0`, `control.choice_1` or `control.choice_2`. Those sockets already mean Player, Tie and Banker respectively. Do not add an `index`, `action`, label or callback field. For Poker, `control.hold_0` through `control.hold_4` are the five stable card indices. For shared Blackjack, seat identity is part of the socket name and cannot be changed through uploaded parameters. Put the manifest into a Blender Text datablock called `betworld-skin.json`, select the existing game anchors, and use **Save skin JSON to selected stations**. Or call `game_skin_save` directly with `revision`, `skin` and `entityIds`. This updates the draft and returns its next revision and budget. A stale revision fails; download and merge deliberately before retrying. For layout changes, add `placements` using the returned `presentation.targets`. Use `clips` for idle/result transforms and `motions` for the game's listed result-motion channels. Export GLB geometry without animation tracks; put bounded numeric keyframes in the skin JSON. The [v2 contract](/game-skin-contract/) specifies units, pivots, timing and endpoints. A skin can be reused by matching game entities. It cannot turn a prop into a game or make an additional station ID available. The same complete skin cannot be assigned to a different game, even if two models look similar. ## 6. Review the actual result Download again into a new Blender scene to inspect the fitted body and socket meshes. The bridge preserves the strict manifest when the world is uploaded later. Blender previews static geometry; platform screens, animated cards, odds and control states are verified in a browser preview of the world. Check the player-height front view, oblique side views, portrait mobile and neighboring stations. Inspect gaps, z-fighting, native labels, the complete hit area and collision paths. Check state-specific geometry: Blackjack split fans and dealer reveal, all three multiplayer seats, Baccarat third cards, all five Poker Holds, Mines 3×3 through 8×8, all Drago difficulties, Keno's eight columns, Dice extremes, Limbo long results, Plinko's entire drop and the full coin-flip envelope. Doubler/Crash need clear reconnecting and live-result displays. Use local preview fixtures for active game states. Check controls, moving parts and approach paths from the player camera, including on your target mobile devices. ## 7. Save the world and publish World uploads preserve the `skins` array and each entity's optional `skin` ID. To revert a station to its native appearance, remove that entity's `skin` field. Remove an unused definition only after no entity refers to it. The owner publishes the saved revision through the website when the world has no active players. Publication revalidates the document, ownership and budgets. MCP credentials cannot publish. Joining players download only the used canonical model hashes along with the world assets, using the existing progress screen. Report the world ID, draft revision, assigned station IDs, skin IDs, asset hashes, byte/triangle/pixel costs, budget response, local `.blend` location and visual states reviewed. Do not claim publication when only the draft was saved, and use v2 placements/clips/motions when the design changes presentation layout or animation. --- # Blender model collection Source: https://docs.betworld.gg/model-gallery/ The garden casino collection uses rounded cream stone, matte teal surfaces, muted gold trim and recessed physical buttons, matching the redesigned Blackjack family. Eleven more game families were modeled in Blender from concepts generated with built-in imagegen. Choose a game below, then switch between its AI concept, Blender model and live browser preview. Browser previews use sample round state. The client supplies actual cards, results, enabled controls and payouts; imagegen placeholder numbers never define game rules. [Imagegen prompts and source manifest](/models/garden-concepts.json). Baccarat retains its original playing-surface-to-player-height ratio. ## Individual previews | Model | Preview | |---|---| | Blackjack | [View Blackjack](/models/blackjack.jpg) | | Baccarat | [View Baccarat](/models/baccarat.png) | | Multiplayer Blackjack | [View Multiplayer Blackjack](/models/blackjack_group.jpg) | | Dice | [View Dice](/models/dice.png) | | Limbo | [View Limbo](/models/limbo.png) | | Mines | [View Mines](/models/mines.png) | | Keno | [View Keno](/models/keno.png) | | Drago Tower | [View Drago Tower](/models/dragontower.png) | | Plinko | [View Plinko](/models/plinko.png) | | Coinflip | [View Coinflip](/models/coinflip.png) | | Video Poker | [View Video Poker](/models/videopoker.png) | | Doubler | [View Doubler](/models/roulette.png) | | Crash | [View Crash](/models/crash.png) | | Midnight player | [View Midnight](/models/player_midnight.jpg) | | Ivory player | [View Ivory](/models/player_ivory.jpg) | | Street player | [View Street](/models/player_street.jpg) | ## Reference downloads Use the [Blender bridge](/blender/) to download your world with correctly scaled game references. For inspection without a world credential, download the [native card and machine library](/downloads/card-dice-tables.glb) and [native prop and display library](/downloads/creator-props.glb). These collections are authoring references, not custom-prop uploads. The first library uses source units; apply the scale in [model-proportions.json](/model-proportions.json) exactly once. Doubler and Crash have their own display scales. The [custom modeling guide](/custom-models/) explains what can be uploaded, how to preserve table-to-player proportions, and how the native controls remain functional. ## Design references Physical-table construction was informed by [TCS John Huxley card tables](https://tcsjohnhuxley.com/product/card-tables/) and its [Baccarat table](https://tcsjohnhuxley.com/product/baccarat-punto-banco-gaming-table/). The cabinet layout was informed by [IGT PeakBarTop](https://www.igt.com/products-and-services/gaming/cabinets/peakbartop). Digital-game presentation references included the [Stake Originals catalog](https://stake.com/casino/group/stake-originals). These references guided the new housings; their game code and branded artwork were not imported as part of this redesign. --- # Use the model reference with an AI Source: https://docs.betworld.gg/model-reference/ [Read as Markdown](/raw/model-reference.md) · [Download game-model-reference.json](/game-model-reference.json) Use this reference to measure the current game models, controls and animation anchors. For replacement bodies and buttons, pair these measurements with the [skin contract](/game-skin-contract/), [socket catalog](/game-skin-catalog.json) and the clearance guide for your game. ## Which reference to use | Resource | Contains | Use it for | |---|---|---| | [game-model-reference.json](/game-model-reference.json) | Actual shipped library hashes, model bounds, physical button bounds and internal reference nodes for all games | Current geometry, physical controls and verifying which library you imported | | [betting-interfaces.json](/betting-interfaces.json) | Runtime table mounts, Poker screen/card targets and legacy fallback deck information | Generated display and card placement that may not exist as a visible GLB mesh | | [model-proportions.json](/model-proportions.json) | Player/body/eye heights, table-plane ratios and display scales | Preserving the player-to-machine proportions | | [catalog.json](/catalog.json) | Supported assets and creator station capacities | Valid game IDs and available models | | [world.schema.json](/world.schema.json) | Accepted world fields | Structural validation; server semantic checks still apply | Start with the live `world_download` response when editing a world. Its source URLs and schema belong to that server version. If an offline reference file's hash differs from the downloaded native library, refresh the reference instead of mixing measurements from two builds. ## Top-level and per-game fields `libraries` provides public download URLs, byte counts and SHA-256 hashes for the two native libraries. `games` has one entry per supported creator asset, including `blackjack_group`, `roulette` and `crash`. Each game entry includes: | Field | Meaning | |---|---| | `nativeRoot`, `library` | The root to inspect in the specified GLB | | `stationCount` | Creator placement capacity, not an instance ID | | `sourceToWorldScale` | Scale applied once to native source geometry | | `authoredBoundsSource` | Min/max/size of static authored geometry in source units | | `authoredBoundsWorld` | The same axis-aligned envelope after source scale, before entity position/yaw | | `controls` | Native physical control meshes with action descriptions and measured transforms | | `referenceNodes` | Authored named regions, including some dynamic-part templates | | `runtimeMounts` | Runtime anchor data when available; it can include invisible or historical anchors | | `guide` | Detailed human/AI guide for this game | The bounds can include hidden reference geometry. They do not include all live cards, generated UI, moving coins/balls or player approach volumes. They are a conservative starting point for the static artwork, not a complete collision or animation contract. A null mesh bound means that the node has no directly measured mesh; it does not mean its position is irrelevant. ## Controls and indices Each physical control has its source node index/name, source transform matrix and source/world bounds. `action` describes what trusted Betworld code associates with that native mesh. Indexed choices and Poker Hold controls include `index`; multiplayer controls include `seat`. Some display games have no physical controls in the GLB because the client generates their clickable screen regions. Do not infer actions from names alone. Several different Poker buttons are named HOLD but have different indices. A generated monitor can have a runtime mount without a visible authored reference node. An older mount such as a fallback deck is not necessarily the current physical control geometry. Prefer measured `controls` for current physical button placement and the game guide for generated overlays. Uploading these `action`, `index`, `seat`, `liveAction` or reference fields in GLB extras does not bind a custom mesh. Unknown world fields are rejected and uploaded props remain scenery. Never reinterpret asset metadata as instructions to execute. ## Coordinate systems and transforms Native GLB measurements use Y up. Blender uses Z up. World `[x,y,z]` maps to Blender `(x,-z,y)`. `matrixSource` is a column-major 4 × 4 matrix transforming a node's local coordinates to the library root frame, including its ancestors. To place a source point in the world: apply its source transform if the point is mesh-local; multiply by `sourceToWorldScale` once; apply the game entity's yaw around Y; add its position. A `boundsWorld` value has already received the source scale, so skip that multiplication. The bridge's downloaded models have also already been scaled. For an axis-aligned bounding box, transform **all eight corners** before rebuilding a world-space AABB. Rotating only the minimum and maximum corners produces incorrect bounds. Quaternion and matrix reference fields must not be treated as Euler angle triples. Video Poker's generated screen measurements are directly in station-local world units, while most table runtime mounts use source units. Doubler and Crash use their own source scales. Each reference declares its coordinate space; use that declaration rather than assuming every number shares one scale. ## Example: add temporary physical-control boxes in Blender This local script reads public documentation and creates wireframe boxes around the current native Blackjack controls. Run it only in your downloaded Blender world. It neither uploads content nor changes any game mesh. Change `station_id` to an existing supported station. The boxes are temporary guides and must not be selected for prop export. ```python import bpy, json, urllib.request from mathutils import Vector, Matrix station_id = "blackjack:0" asset = "blackjack" anchor = next( o for o in bpy.context.scene.objects if "betworld_entity" in o and json.loads(o["betworld_entity"]).get("id") == station_id ) with urllib.request.urlopen( "https://docs.betworld.gg/game-model-reference.json", timeout=30 ) as response: reference = json.load(response) guides = bpy.data.collections.new("TEMP control clearance guides") bpy.context.scene.collection.children.link(guides) for control in reference["games"][asset]["controls"]: bounds = control["boundsWorld"] if bounds is None: continue lo, hi = Vector(bounds["min"]), Vector(bounds["max"]) center, size = (lo + hi) / 2, hi - lo # Bounds are already world-scaled, but remain station-local. local_center = Vector((center.x, -center.z, center.y)) dimensions = Vector((size.x, size.z, size.y)) padding = 0.08 # Visual working margin, not a complete approach envelope. bpy.ops.mesh.primitive_cube_add(size=1) box = bpy.context.object box.name = "TEMP " + control["action"] for collection in list(box.users_collection): collection.objects.unlink(box) guides.objects.link(box) box.matrix_world = ( anchor.matrix_world @ Matrix.Translation(local_center) @ Matrix.Diagonal(Vector(( dimensions.x + padding, dimensions.y + padding, dimensions.z + padding, 1 ))) ) box.display_type = 'WIRE' box.hide_render = True box.hide_select = True ``` The margin is an authoring aid, not a validated reach/collision rule. Also mark live screens, card paths, coin/ball travel and approach space described by the game's guide. Delete or exclude the temporary collection before export. The uploader can include selected mesh guides even if they were intended only as helpers. ## Diagnose common mistakes | Symptom | Check | |---|---| | Everything is about 1.568 times too large | Native source scale may have been applied twice | | Screen frame fits the GLB but not the game | You may have omitted a generated overlay or used a legacy mount as current geometry | | Buttons fit from above but cannot be seen while playing | Review eye-height sightlines and the front approach | | A hollow prop blocks movement | The current prop collider is its box; split solid pieces | | A rotating machine leaves trim/rug behind | Each prop is a separate entity; apply the same assembly transform | | New uploaded button does nothing | Props have no user-authored action binding | | A display has no `controls` entries | Check its guide for runtime screen interaction regions | | Coin or ball clips through a sign | Static bounds do not cover the animation envelope | | Model looks fine locally but is absent in the world | Upload asset, save its prop entity, publish the draft and join that published revision | Use the [complete workflow](/model-authoring-workflow/) and [per-game guides](/betting-models/) for the rest of the process. --- # Publish and earn Source: https://docs.betworld.gg/publishing/ ## Publish a saved draft In the world builder, choose **Publish** to save your changes and queue that exact revision. You can also select a world under **Your worlds**, choose **Reload saved changes** and then **Publish world**. The server revalidates the document, asset ownership and every budget. At least one supported game station is required. If the revision is stale, reload before retrying. Players see **Update incoming** and new bets in that world are blocked. Existing hands and rounds continue; players can finish their actions, draw or cash out. Waiting PvP coinflips can be cancelled by their creator or expire after ten minutes. After at least five seconds of notice, the queued layout is applied when all accepted bets have settled. Other worlds continue normally. Connected players automatically load the new 3D world without reloading the page. The queued revision is a snapshot: later draft edits do not change it. A queued update survives a server restart. Use **World → Cancel pending update** in the builder to reopen betting without applying it. Publish and cancellation use your authenticated owner session. AI credentials can save drafts and upload models. Use **Play world** to enter the published version yourself. ## What players receive The world browser shows the published world. On join, players fetch the published document and download its required assets with a loading-progress screen. They enter after construction finishes. The public lobby's board ranks active worlds by player count. Cloudflare checks the current approved revision with Betworld's server, then delivers its layout and referenced models, textures and audio from R2. Published layouts are immutable snapshots; drafts remain private on the server. WebSocket notifications tell connected players when a new revision is ready. The server continues to authorize every game and settle every bet independently of the downloaded layout. An unpublished draft is not joinable by other players. Further draft edits do not change the published version until the next successful publication. ## Earnings calculation The owner receives **10% of user edge (the theoretical house edge) on settled wagers** placed in their world. For a $100 wager with a 1% theoretical edge: ```text $100 × 0.01 × 0.10 = $0.10 owner earnings ``` The result does not depend on whether that individual player wins or loses. Earnings use the edge recorded by the game settlement, not a client-supplied edge or creator setting. The 10% rate applies to settlements after the rate-change migration. Earlier accruals keep their recorded 5% rate, including their unpaid fractional carry. Earnings are credited automatically in increments of **$0.0001** after settlement processing. Smaller fractions carry forward until they reach that amount. For example, two settlements earning $0.00005 each produce a spendable $0.0001. Each settled wager contributes once. Betworld uses 10,000 integer accounting units per dollar. API fields named `paidCents`, `earnedCents` or `availableCents` are expressed in cents and can include two decimal places: `0.01` cents is $0.0001. Crypto amounts remain in each network's native atomic units. ## Ownership and active bets A world's owner is fixed. Tokens cannot transfer ownership or redirect the beneficiary. Players must actually join the creator world before attributing a bet to it. Game availability is checked against that world's published station list. Disconnecting the final player unloads ephemeral room state; durable wager and accounting records remain. Accepted bets still settle or recover according to the game's rules. Publication does not erase history or change past earnings. --- # Your first world Source: https://docs.betworld.gg/quickstart/ ## 1. Create a starting world Sign in at [betworld.gg](https://betworld.gg), open **Create world**, enter a name and click **Create world**. Your draft starts with the basic creator layout and supported betting tables. You can own up to three worlds. Guests can explore the public meadow lobby. Creating worlds, joining betting worlds, chatting and betting require an account. ## 2. Arrange your world Creating a world opens the 3D builder. Pick an asset from the right panel, then click or tap the floor to place it. Select a placed object and use **Move**, **Rotate** or the numeric inspector to arrange it. Props also support resizing and tinting. **Upload** accepts your own static GLB models up to 4 MB each. Drag empty space to orbit, right-drag to pan and scroll to zoom. On touch devices, use one finger to orbit and two to pan or zoom. The [world builder guide](/in-game-editor/) covers every tool and shortcut. ## 3. Save and publish Choose **Save draft** to retain your private layout. When it is ready, choose **Publish**. New bets pause and players see **Update incoming**. Existing games finish before the server applies the update. Players automatically reload the 3D world, keeping the rest of the page in place. At least one supported game station is required. The server validates your assets, layout and budgets before queueing publication. Choose **Play world** after the publication completes. ## 4. Return and keep building In a world you own, open the Escape menu and choose **Edit this world**. You can also select it in **Your worlds** and choose **Open world builder**. Your saved draft loads into a private workspace while other players continue in the published world. ## Optional: connect your AI Choose your world and click **Create MCP credential**. Copy the generated server configuration into a compatible MCP client. It contains the server URL and a private Bearer credential scoped to that one world's draft. The token does not expire automatically. It remains valid until revoked or replaced. A newly generated token replaces the previous token for that world. Use **Revoke access** to end access immediately. Give your assistant the [agent guide](/agent-guide/) or [complete docs](/llms-full.txt). If it will operate Blender, also connect a local Blender MCP server in your AI client. The remote Betworld MCP saves world data; the local Blender MCP manipulates your local Blender scene. ### Ask for a concrete design Example prompt: > Read https://docs.betworld.gg/llms-full.txt. Use the connected Betworld MCP to download my draft and inspect its revision, catalog and limits. In Blender, build a compact garden casino with ivory paths, teal felt, low hedges and distinct Blackjack, Baccarat and Drago Tower areas. Preserve game dimensions and entrance clearance. Reuse prop assets, keep paths walkable, then upload a draft. Report the revision, entity count, estimated memory and total download size. Do not publish it. Begin with a small scene. Validate one custom prop before producing many assets. Ask your AI to work in reviewable stages rather than placing hundreds of thousands of objects at once. Your assistant saves the same draft used by the in-game builder. Save your local changes before switching tools, then choose **World → Reload saved draft** to see the assistant's changes. Revision conflicts protect newer saves from being overwritten. --- # Access and upload requirements Source: https://docs.betworld.gg/security/ ## Choose your authentication method | Task | Authentication | | --- | --- | | Browse published worlds and download published assets | Public | | Create a world, view your earnings, publish a revision | Your registered website session | | Create, replace or revoke a world credential | Your registered website session | | Download or edit a connected draft | Its world token, or your owner session | | Upload world props and game-skin meshes | Your world token, or your owner session | | Upload your personal avatar | Your registered website session | Create a credential from **Create world → Create MCP credential**. Save it in your AI client's secret settings and send it as `Authorization: Bearer YOUR_TOKEN`. Each credential selects one world and grants access to its owner's asset library. It stays valid until you revoke access or create a replacement. Revoking a credential preserves your saved world and assets. See [Connect your AI](/connect-mcp/) for client setup and the [World HTTP API](/world-api/) for each route's authentication and request format. ## Prepare the right file | Content | Upload format | Source file limit | Guide | | --- | --- | --- | --- | | Scenery and props | Static, self-contained GLB | 4,000,000 bytes | [Custom assets](/assets/) | | Game bodies, buttons and surfaces | Separate static GLBs plus a skin manifest | 4,000,000 bytes per GLB | [Game skin contract](/game-skin-contract/) | | Personal avatar | Rigged GLB, VRM or supported Unity package | 30,000,000 bytes; 3 attempts per rolling hour | [Custom avatars](/avatar-imports/) | | World layout | JSON world document | 64,000,000 bytes per save request | [World format](/world-format/) | Embed textures in world GLBs. Export final geometry with transforms applied. World props use static meshes and materials; avatar uploads use the humanoid rig requirements in their guide. Upload artwork you have permission to distribute to other players. ## Connect your custom controls Fetch `game_skin_contract` for the game you are building. Upload a body and any button meshes, then bind their returned asset hashes to the catalog's named slots with `game_skin_save`. Betworld supplies the control action, game state, live displays and result animations. Your manifest supplies the artwork for each slot. The manifest schema accepts only the documented fields. Use [the per-game guides](/betting-models/) for exact buttons, dimensions and clearance requirements. ## Keep your connection private Store credentials outside exported scenes, screenshots and source control. Connect Blender MCP on your own workstation and install the [Betworld Blender bridge](/blender/). Send the world token only to the Betworld origin configured in your client. If you share a credential accidentally, create a replacement in the world panel and update your AI client. The previous credential stops working immediately. For a `401`, reconnect with the current token; for a `409`, download the latest draft and save against its revision. --- # Terrain and backgrounds Source: https://docs.betworld.gg/terrain-backgrounds/ ## Use the editor Open **World** in the editor's asset panel. Set **Layout → Outdoor**, then choose **Meadow**, **Desert**, **Rocky** or **Flat**. Change the size, hill height, roughness or seed. **New seed** generates a different arrangement; **View terrain** frames the landscape. The central build area remains level. Place props and stations within X/Z ±half your selected **Build area** width (56–384 metres); the generated terrain extends around that area and is walkable. A player reaching the outer boundary returns to spawn. Changing the seed preserves your placed entities. Terrain settings support Undo and Redo. Choose **Sky** or **Lobby panorama** under **Background**, or select **Upload panorama**. Accepted uploads appear in the same selector and can be reused in your other worlds. Adjust **Background rotation °** to align the view with your layout. Terrain and background changes are part of the draft. **Save draft** stores them; **Publish** queues the world update after current bets finish. Set **Layout → Room** to restore the enclosed room. This removes terrain and background settings from the draft; uploaded images remain in your library. ## Prepare a panorama Use a still PNG, JPEG or WebP with these limits: | Property | Limit | | --- | --- | | Input file | 12,000,000 bytes | | Width | 512–8192 pixels | | Height | 256–4096 pixels | | Aspect ratio | 2:1 through 8:1, width divided by height | | Decoded pixels | 16,777,216 | | Converted WebP | 8,000,000 bytes | A seamless **2:1 equirectangular panorama**, such as 4096 × 2048, covers the full sphere. A wider panorama, such as 8192 × 2048, covers a band around the horizon and fades into the sky above and below. Keep the horizon near the middle, align the left and right edges and bake the image in landscape orientation. Panoramas with a rotated EXIF orientation are rejected; export the actual pixels in the intended orientation first. The renderer softens the join and poles, but matching the source edges gives the best result. The converter retains the source dimensions, strips metadata, flattens transparency and encodes a new WebP. Only the converted image is stored and displayed. SVG, GIF, animated WebP, archives and URLs are not accepted. Processing uses the isolated, networkless image worker. Models and converted backgrounds share your **100 MB library allowance**. A referenced panorama also counts toward the world's **100 MB download**, **32 megapixel texture** and **500 MB estimated memory** limits. A maximum-size panorama may leave too little memory for a complex world; the save response reports the combined budget. ## World document fields Keep `version: 1`, `floor`, `walls` and `entities`. Add either or both of these optional fields: ```json { "terrain": { "preset": "desert", "seed": 42, "size": 256, "height": 9, "roughness": 0.45 }, "background": { "mode": "lobby", "yaw": 0 } } ``` The example shows the environment fields to merge into your complete document. | Terrain field | Required value | | --- | --- | | `preset` | `meadow`, `desert` or `rocky` | | `seed` | Integer 0–2,147,483,647 | | `size` | Integer 128–512 and at least `buildSize + 64`; full square width in game units | | `height` | Finite number 0–28; maximum terrain amplitude | | `roughness` | Finite number 0–1; contribution of smaller hills | The same settings generate the same terrain. Geometry uses a fixed 192 × 192 grid: 37,249 vertices and 73,728 triangles. The center remains flat through ±`(buildSize / 2 + 6)` units (±34 at the default build size), then transitions into hills. Collision uses the generated mesh. The return boundary is three units inside each outer edge. Terrain geometry counts toward the geometry and estimated memory budgets; the world stores only its parameters. | Background field | Required value | | --- | --- | | `mode` | `sky`, `lobby` or `image` | | `yaw` | Finite radians, −2π through 2π | | `asset` | Required only for `image`: a 64-character lowercase hex hash from your background library | For an uploaded image: ```json {"mode":"image","asset":"","yaw":1.5707963267948966} ``` Omit `terrain` for flat outdoor ground. Omit both `terrain` and `background` for the enclosed room. A background alone creates a square of flat ground with width `max(128, buildSize + 64)` and the `floor` color. Change the root `buildSize` field to enlarge the placement area. The editor automatically increases terrain width if enlarging the build area requires it; API clients must send compatible values together. Game dimensions remain unchanged. There is no separate background URL, shader or expression field. ## Upload through HTTP With a world-scoped Bearer credential: ```bash curl --fail-with-body \ -X POST https://betworld.gg/api/worlds/ai/backgrounds/upload \ -H "Authorization: Bearer $BETWORLD_TOKEN" \ -H "Content-Type: image/webp" \ -H "X-Image-Name: Desert sunset" \ --data-binary @desert-panorama.webp ``` Send raw image bytes. Accepted content types are `image/png`, `image/jpeg`, `image/webp` and `application/octet-stream`. `X-Image-Name` is an optional trimmed name, 1–80 characters; it defaults to `Panorama`. Use ASCII for this HTTP header. The authenticated owner-session equivalent is `POST /api/worlds/backgrounds`. Successful response, HTTP 201: ```json { "hash": "<64-character-hash>", "name": "Desert sunset", "size": 1843200, "width": 4096, "height": 2048, "pixels": 8388608 } ``` Download the converted result from `GET /api/worlds/backgrounds/.webp`. This immutable public route returns `image/webp`. A creator can reference only hashes in their own library, even when another creator's public image URL is known. `GET /api/worlds/mine`, `GET /api/worlds/:id/draft`, `GET /api/worlds/ai/draft/document` and `GET /api/worlds/ai/export/world` include a `backgrounds` array with these metadata fields. The export also includes each background's `url`. `/mine` reports `usedBytes` for models and backgrounds together. The existing `assets` array continues to contain only GLB models. After upload, fetch the latest draft, set `document.background`, and save the complete document with its current `revision`. Uploading alone does not modify or publish the world. | Status | Meaning | | --- | --- | | 400 | Invalid fields, library quota, missing/foreign background, or world budget exceeded | | 401 | Sign-in or world credential required | | 404 | Background hash does not exist | | 413 | Request body exceeds the upload limit | | 422 | Image could not be converted within its format, dimension or processing limits | | 429 | Request rate or concurrent-write limit reached | | 503 | Converter is busy or unavailable; retry later | ## Upload through MCP Call `background_upload` with: ```json { "name": "Desert sunset", "imageBase64": "" } ``` The decoded image has the same 12 MB limit. The tool returns the metadata shown above. Use `world_download`, update `document.terrain` and/or `document.background`, then call `world_upload` with the returned revision and the complete document. Preserve entities, game skins and any other settings. Publish from your owner session in Betworld. The Blender bridge preserves terrain and background settings during download/upload round trips. Its scene preview still uses the base room shell; inspect the generated landscape and panorama in the in-game editor. --- # Troubleshooting Source: https://docs.betworld.gg/troubleshooting/ ## Credential invalid, revoked or replaced New credentials do not expire automatically. Credentials that were still valid when the no-expiry policy was introduced were upgraded; already-expired credentials were not reactivated. If a credential was revoked, replaced or expired under the previous policy, create a new credential for the same world and replace it in both your AI client and Blender sidebar. Generating a credential revokes its predecessor. Do not retry an old token indefinitely or paste tokens into public support messages. ## MCP connects but no tools appear Confirm the URL ends in `/api/worlds/ai/mcp`, the client supports Streamable HTTP with custom Bearer headers, and it completed initialization. GET 405 is expected for the unused persistent stream. Clients that insist on OAuth discovery need a compatible client or bridge instead. The docs hostname is not the MCP endpoint. Reading docs does not authenticate a client to your world. ## Draft changed in another editor Another save incremented the revision. Download the current draft and merge the intended changes, then submit its revision. The in-game builder, another browser, an AI session and the Blender bridge share the same draft revision. In the builder, download your unsaved changes before choosing Reload latest. ## Missing prop or unknown asset Use a built-in asset from the returned catalog or an uploaded hash owned by your account. An asset uploaded by another creator cannot simply be referenced by copying its hash. Upload a legitimate copy to your own library if you have permission to use it. ## GLB rejected Check that it is a static GLB with embedded buffers and images. Remove rigs, animations, morph targets, unsupported extensions, external resources, extras, cameras and lights. Use PNG/JPEG/WebP textures no larger than 2048 pixels per side, and keep the converted output below 4 MB. Export a small test prop first. ## Memory, download or geometry budget exceeded Read the exact error. Each limit is independent. Reuse assets, reduce texture resolution and mesh parts, reduce placed copies, or combine fine static detail. The 100 MB download limit counts the manifest and standard assets as well as uploaded GLBs. A small compressed file can still exceed the decoded memory budget. ## Game scale or station error Keep game Y at zero, scale at `[1,1,1]`, and use an available `:` ID. Multiplayer Blackjack seats belong to their parent `blackjack_group` table. Unknown game names and duplicate station IDs are rejected. ## An update is waiting for games to finish New wagers are paused while accepted bets settle. Finish your hand, draw or cash out where the game allows it. Creators of waiting PvP coinflips can cancel them to return their stake; unmatched flips also expire under the ten-minute rule. The update applies automatically after settlement. To keep the current layout, open the builder’s World tab and choose Cancel pending update. ## Published changes are missing Confirm the published revision matches the intended draft revision, then leave and rejoin. Saving through MCP changes the draft only. Cached immutable model URLs remain valid because changed model contents receive different hashes. ## Paths are blocked or performance is poor Props use box-shaped collision; concave shapes can block their empty center. Split doorframes and arches into separate solid pieces. Reduce dense overlapping objects and high-poly copies. Inspect the world on a modest device as well as a desktop GPU. ## Server busy 503 with `Retry-After` means bounded admission rejected concurrent heavy work. Retry with backoff and jitter, one draft revision at a time. 429 means rate limiting. A 413 response means the request body exceeded its transport limit. These errors should not be solved by retrying many requests in parallel. --- # World HTTP API Source: https://docs.betworld.gg/world-api/ [Read as Markdown](/raw/world-api.md) · [MCP tools](/mcp-tools/) · [World schema](/world.schema.json) ## Base URL and authentication Use `https://betworld.gg/api/worlds`. All JSON requests use `Content-Type: application/json`. GLB uploads use `Content-Type: model/gltf-binary` and raw file bytes. | Access | How to authenticate | Use for | | --- | --- | --- | | Public | No credential | Browse published worlds and download published documents or assets | | Owner session | Your signed-in Betworld session cookie | Create worlds, manage credentials, inspect your library and publish | | World token | `Authorization: Bearer ` | Let your AI read and edit one world draft and upload assets to your library | Sign in with a registered account for owner routes. In the Betworld website, use `fetch` with `credentials: "same-origin"`; your browser supplies the session cookie and `Origin`. Session-based write requests require `Origin: https://betworld.gg`. For token-based `/ai/...` requests, a command-line or MCP client can omit `Origin`. If supplied, it must match the Betworld origin. Create a token for each world you connect. Tokens remain valid until you revoke or replace them. Store the token in your AI client's secret settings. Owner-session actions, including publishing, are available through your signed-in website session. ## Route index Paths below are relative to `/api/worlds`. | Method | Path | Access | Result | | --- | --- | --- | --- | | GET | `/` | Public | Active world directory, lobby population and limits | | GET | `/mine` | Owner | Your worlds, asset library, usage and earnings | | POST | `/` | Owner | Create a world with a basic starting layout | | GET | `/:id/document` | Public | Published document and published revision | | GET | `/:id/status` | Owner | Draft revision, published revision and entity count | | GET | `/:id/draft` | Owner | Your editable document and asset library | | PUT | `/:id/draft` | Owner | Replace your draft using its current revision | | POST | `/:id/publish` | Owner | Publish a saved revision | | POST | `/:id/ai-token` | Owner | Create or replace the world's AI credential | | DELETE | `/:id/ai-token` | Owner | Revoke the world's AI credential | | POST | `/assets` | Owner | Upload a static GLB to your library | | GET | `/assets/:hash.glb` | Public | Download an immutable converted GLB | | GET | `/ai/draft/document` | World token | Read the connected draft, catalog, limits and schema | | PUT | `/ai/draft/document` | World token | Replace the connected draft | | GET | `/ai/export/world` | World token | Download the draft with asset URLs and Blender references | | POST | `/ai/assets/upload` | World token | Upload a static GLB to the connected owner's library | | POST | `/ai/mcp` | World token | Call the [MCP tools](/mcp-tools/) using JSON-RPC | ## Browse and download ### GET `/` Returns: ```json { "worlds": [ {"id":"public-2","name":"Pyramids","description":"…","ownerId":null,"revision":1,"players":12,"capacity":50} ], "hub": {"id":"lobby","name":"Lobby","players":4}, "limits": {"entities":1000000,"memoryBytes":500000000,"worldBytes":100000000} } ``` The numbers and description above are examples; `limits` contains the full current limit object. Worlds are ordered by descending active player count, then ID. Creator worlds have an `ownerId`; built-in worlds use `null`. `revision` here identifies the published version. ### GET `/:id/document` Returns `{ "id", "name", "document", "revision" }` for a published world. Use this document to inspect the layout players receive. A missing or unpublished world returns `404`. Your newer draft is available through an owner or token draft route. ### GET `/assets/:hash.glb` Replace `:hash` with a returned 64-character lowercase hexadecimal asset hash. The response body is binary `model/gltf-binary`. Asset URLs are immutable and publicly downloadable; keep private material out of assets you upload. Cache responses for repeat visits. Missing hashes return `404`. ## Create and manage your worlds ### POST `/` Request: ```json {"name":"My Desert World","description":"Tables beneath the palms."} ``` `name` is trimmed and must contain 3–48 characters. `description` is optional, trimmed, defaults to an empty string and permits 240 characters. Extra fields are rejected. The JSON request limit is 2 KiB. You can own up to three worlds. Success: `201` with `{ "id": "world-" }`. The new draft starts with the basic layout. Read its draft to get the initial revision before editing. ### GET `/mine` Returns: - `worlds`: your worlds, each with `id`, `name`, `description`, `revision`, `published_revision` and `updated_at`. - `assets`: your library entries, each with `hash`, `name`, `size`, `triangles`, `pixels` and `meshes`. - `usedBytes`: total converted bytes in your asset library. - `earnings.paidCents`: earnings already paid to your balance, in cents. - `earnings.pendingUnits`: the fractional remainder as a decimal string; 1,000,000 units equal one cent. Divide by 1,000,000 to display pending cents. - `limits`: current creator and world budgets. Library entries are ordered by creation time. `meshes` counts rendered primitive parts and contributes to the estimated memory budget. See [publishing and earnings](/publishing/) for the earning formula. ### GET `/:id/status` Returns `{ "id", "name", "revision", "publishedRevision", "entities" }`. Use this lightweight request to refresh the management page after your AI saves a change. A world you do not own returns `404`. ### GET `/:id/draft` Returns `{ "id", "name", "description", "document", "revision", "publishedRevision", "assets" }`. `document` is the complete editable world. Use its `revision` in your next save. ## Save a draft Use **PUT `/:id/draft`** with your owner session, or **PUT `/ai/draft/document`** with the connected world's token. Both accept the same body: ```json { "revision": 1, "document": { "version": 1, "floor": "#dad4c4", "walls": "#e8e1cf", "entities": [ {"id":"blackjack:0","kind":"game","asset":"blackjack","position":[-8,0,4],"yaw":0,"scale":[1,1,1],"color":"#d7ba7f"}, {"id":"bench-east","kind":"prop","asset":"bench","position":[8,0,4],"yaw":3.141592653589793,"scale":[1,1,1],"color":"#42756b"} ] } } ``` This replaces the complete draft, including entities and optional `skins`. Preserve every field and entity you want to keep. The body limit is 64,000,000 bytes, including the revision/document envelope. Follow the [world format](/world-format/) and [game skin contract](/game-skin-contract/) for exact field and placement rules. Success returns: ```json { "revision": 2, "budget": { "entities": 2, "bytes": 25000306, "manifestBytes": 306, "memoryBytes": 138667738, "triangles": 110060, "pixels": 8000000 } } ``` Budget values are illustrative. Use the actual returned values. `revision` increases after every accepted save; submit that new revision next time. Publishing is a separate step. If you receive `409`, download the current draft, merge your changes into it, and retry using its revision. Keep saves sequential. For smaller edits, use MCP `world_edit_entities` to upsert/remove up to 1,000 entities per array. ## Publish ### POST `/:id/publish` Request: `{ "revision": 2 }`, using your latest saved revision. The JSON request limit is 1 KiB. The revision must match the saved draft, the draft must contain a supported game station, all referenced assets must belong to your library, and every world budget must pass. Success returns `{ "ok": true, "pending": true, "revision": 2 }`. The server stores that exact draft as a pending snapshot, blocks new wagers in the world, and waits for existing bets to finish. After at least five seconds of notice and no unsettled wagers, it installs the snapshot. Later draft saves do not change the pending snapshot. A stale revision or a different update already queued returns `409`. Repeating the same queued revision succeeds without replacing or delaying it. Use an authenticated owner session. ### GET `/:id/update` Public, uncached metadata for polling publication progress: ```json { "revision": 1, "pending": true, "pendingRevision": 2, "requestedAt": "2026-11-01T12:00:00.000Z" } ``` `revision` is the currently published revision, or zero for an unpublished world. `pendingRevision` and `requestedAt` become `null` when no publication is pending. While `pending` is true, clients show the update notice and disable new-bet controls while keeping active-game actions enabled. When `revision` increases, download `GET /:id/document` and reload the world renderer. The website does this automatically without replacing the page. ### DELETE `/:id/publish` Authenticated owner session, no body. Cancels a queued update and returns `{ "ok": true }`. The existing published layout and saved draft are retained; new bets reopen. It does not roll back a publication that already completed. ## Create, replace or revoke an AI token ### POST `/:id/ai-token` Send an authenticated owner request with no body. Response: ```json { "token": "<64 lowercase hexadecimal characters>", "endpoint": "https://betworld.gg/api/worlds/ai/mcp", "draftEndpoint": "https://betworld.gg/api/worlds/ai/draft/document", "expiresIn": null } ``` Save the returned token immediately in your client's secret settings. Calling this route again replaces the previous credential for that world. `expiresIn: null` means the credential has no automatic expiry. ### DELETE `/:id/ai-token` Send an authenticated owner request with no body. Returns `{ "ok": true }`. The credential stops working; your saved draft, assets and published world remain available to you. ## Read the connected world with a token ### GET `/ai/draft/document` Returns `worldId`, `revision`, `document`, `assets`, `catalog`, `limits` and `schema`. The token selects your world automatically. `catalog.props` and `catalog.games` contain supported built-ins; `schema` describes the accepted world JSON. ```bash curl --fail-with-body https://betworld.gg/api/worlds/ai/draft/document \ -H "Authorization: Bearer $BETWORLD_TOKEN" ``` ### GET `/ai/export/world` Use this when importing a draft into Blender. It returns the same core draft data plus: - `name`: the world name. - `assets[].url`: an immutable download URL for each asset in your library. - `sources.props`, `sources.games`, `sources.shell`: GLB authoring references. - `gameScale`: the source-to-world scale for the game library. - `authoring`: URLs for model guides, interfaces, the skin contract, socket catalog and skin schema. Preserve the supplied game scale when placing reference models. The [Blender bridge](/blender/) handles coordinate conversion and reference placement for you. ## Upload a prop or game-skin mesh Use **POST `/assets`** with your owner session or **POST `/ai/assets/upload`** with your world token. ```bash curl --fail-with-body https://betworld.gg/api/worlds/ai/assets/upload \ -H "Authorization: Bearer $BETWORLD_TOKEN" \ -H 'Content-Type: model/gltf-binary' \ -H 'X-Model-Name: Palm planter' \ --data-binary @palm-planter.glb ``` Send one static, self-contained GLB of at most **4,000,000 bytes**. The converted result must also fit that limit. `X-Model-Name` is optional; it defaults to `Custom prop` and permits 1–80 characters after trimming. Use embedded textures within the [asset limits](/assets/). Your entire converted asset library can use 100,000,000 bytes. Success: `201` with `{ "hash", "name", "size", "triangles", "pixels", "meshes" }`. `size` is the converted byte count. Place the prop using `asset: "upload:"`, or use the plain hash as a skin's `body` / binding `asset`. Save the draft after uploading to include the placement or skin. Re-uploading identical converted content under the same owner reuses its hash and storage. Revised geometry or materials can produce a new hash; update your document to reference the returned asset. Existing assets continue to occupy library storage. For player characters, use the separate [avatar upload API](/avatar-imports/), whose formats and size limits differ. ## MCP transport Send JSON-RPC requests to **POST `/ai/mcp`** with your world token. Start with `initialize`, honor its returned protocol version, then call `tools/list` or `tools/call`. Use `Accept: application/json, text/event-stream`; parse either response format. The transport is stateless; a persistent GET event stream returns `405`. ```json {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"world_download","arguments":{}}} ``` The [MCP reference](/mcp-tools/) documents all seven tools: `world_download`, `world_upload`, `world_edit_entities`, `game_skin_contract`, `game_skin_save`, `asset_upload` and `asset_download`. Successful tool results contain `structuredContent` and equivalent JSON text. Check `isError` on tool results even when HTTP returns `200`. ## Errors, limits and retrying Application validation failures return `{ "error": "message" }`. Read that message before retrying. Rate-limit and proxy errors may use a text body; check the response Content-Type before parsing JSON. | HTTP status | What to do | | --- | --- | | 400 | Correct the request, model, placement, ownership reference or resource budget described by `error` | | 401 | Sign in to a registered account, or reconnect using your current world token | | 403 | Use the correct origin and authentication method for the route | | 404 | Check the world/asset ID, publication status and world ownership | | 409 | Refresh a stale draft revision, or cancel an existing queued update before publishing a different revision | | 413 | Reduce the request body to the route's byte limit | | 429 | Wait for the rate-limit window indicated by response headers | | 503 | Respect `Retry-After` and retry after the service has capacity | | 500 | Retry a read later; refresh the draft before repeating a save whose outcome is uncertain | World API routes allow 120 requests per minute per client IP. Public GLB downloads have a separate 12,000-per-minute limit. Heavy reads and writes are admitted one at a time; queue your AI's changes instead of sending parallel saves. Proxy limits can also apply. All limits apply together: up to 1,000,000 entities, 100 MB world download, 500 MB estimated runtime memory, 64 MB manifest, 20,000,000 placed triangles, 32,000,000 decoded texture pixels and 50 players per world. Read the live `limits` response and returned `budget` while building. ## In-game editor integration `GET /:id/document` includes `ownerId` alongside `id`, `name`, `document` and `revision`. The site offers Edit this world when it matches the signed-in player. Ownership is checked independently on every draft, asset and publish operation. `GET /:id/draft` also returns `pendingRevision` (an integer or null). The editor uses it to resume displaying a queued publication after reopening. Draft saves continue to use the current `revision`; queued publication uses its own stored snapshot. ## Terrain and panorama routes World documents accept optional `terrain` and `background` settings. Upload a background with `POST /api/worlds/backgrounds` using your owner session, or `POST /api/worlds/ai/backgrounds/upload` using a world Bearer credential. Download canonical WebP bytes from `GET /api/worlds/backgrounds/:hash.webp`. Draft, library and export responses include `backgrounds` metadata alongside the existing GLB `assets`. See [terrain and backgrounds](/terrain-backgrounds/) for every field, limit, header, response and error code. --- # World document format Source: https://docs.betworld.gg/world-format/ A world document contains `version`, `floor`, `walls` and `entities`, with optional `buildSize`, `skins`, `terrain` and `background`. Unknown fields are rejected. | Field | Format | |---|---| | `version` | Integer `1` | | `floor`, `walls` | Six-digit hex colors such as `#e8ddc6` | | `buildSize` | Optional integer 56–384; placement square width. Defaults to 56. | | `entities` | Array of placed props and game stations | | `terrain` | Optional seeded terrain parameters; see [terrain and backgrounds](/terrain-backgrounds/) | | `background` | Optional sky, lobby panorama or owned image hash and rotation | | `skins` | Optional game skin manifests | Each entity must contain all seven fields: | Field | Rules | |---|---| | `id` | 1–80 ASCII letters, digits, colon, underscore or hyphen; unique in the world | | `kind` | `prop` or `game` | | `asset` | Built-in prop/game name, or `upload:` followed by an owned 64-character lowercase hex hash | | `position` | `[x,y,z]`; X/Z within ±`buildSize / 2`; Y 0…64 | | `yaw` | Finite radians from −2π through 2π | | `scale` | Three finite values, each 0.1…12; games require exactly `[1,1,1]` | | `color` | Six-digit hex color | The reserved entrance region rejects origins with `abs(x) < 3` and `z > buildSize / 2 - 6`. NaN, infinities, duplicate IDs, extra script fields, foreign asset hashes and URL-valued asset references are rejected. ## Game identity A game's ID is `:`, for example `blackjack:0`, `dice:0` or `blackjack_group:0`. The index must be available in the live catalog. Games use unit scale and may sit at any floor elevation from Y = 0 to 64. Their native geometry and all interactions move together with the entity. The schema cannot express every cross-field rule; the server enforces these semantics as well. Ordinary Blackjack stations use indices 0–10. Shared multiplayer seats are generated by the two `blackjack_group` stations, indices 0–1. Do not place their shared seats as independent Blackjack tables. ## Built-in props Available props are `floor`, `wall`, `doorway`, `windowwall`, `stairs`, `ramp`, `block`, `pillar`, `carpet`, `bench`, `planter` and `bar`. The six modular pieces come from [building-kit-v1.glb](/downloads/building-kit-v1.glb). See [Build in the game](/in-game-editor/#build-floors-and-structures) for dimensions and openings. Their geometry is supplied by the platform template GLB. Custom GLB props use normalized source geometry; placement scale controls their dimensions. Props use instanced rendering. Modular doorway/window pieces have open collision, and stairs/ramps use walking slopes. Other props use box-shaped collision. They are static. Build enterable structures from separate wall, floor and stair entities, leaving openings between them; a single uploaded building shell has a solid bounding box. In room mode, the floor expands with `buildSize` and the ceiling rises for elevated objects. The entrance spawn is `[0, 0, buildSize / 2 - 2]`. In outdoor mode, terrain must be at least `buildSize + 64` wide. Resize the document before moving entities beyond its current bounds. Game models have their platform interaction geometry and controls. Large props can obstruct paths even if their origins are valid, so inspect the playable scene. ## Draft and published revisions Draft revisions start at 1 and increment on successful saves. Every save requires the current revision. Published content changes only when the owner publishes. Players join the published revision, not the latest draft. Fetch the [JSON schema](/world.schema.json) for structural validation and [catalog](/catalog.json) for current supported assets. Budget enforcement, ownership and game semantics remain server-side even if your JSON schema validator accepts a document. ## Optional game skins The top-level strict document accepts optional `skins`, an array of up to 32 [v1 or v2 skin manifests](/game-skin-contract/). A game entity may include `"skin": "my-skin-id"`. The definition must exist, its `game` must equal the entity `asset`, its fingerprint must match that game, and every referenced model must be in the authenticated creator library. Props cannot use `skin`. Skin IDs are unique within the document. Unused definitions still undergo schema and ownership validation. Omit the entity field to use native visuals. Skin definitions are saved and published with the world revision. `world_upload`, draft PUT and `game_skin_save` enforce the same ownership, revision and budget constraints. This field never enables scripts, additional action types, dynamic parameter expressions or external asset URLs.