# Use the model reference with an AI [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.