Gears and turning parts
Example: Gear Works (a gear from a model, a data-declared clockwork motor, a placement guide).
Gears are part of the game, in Movement: Gear Size 1 to Gear Size 8 (16 teeth a size), Hollow Gear Size 3 to 8 (teeth outside and in, its middle open), Rack Gear and Gear Shaft. The palette shows a Gear tile (every solid size, Size 1 at first) and a Hollow Gear tile (Size 3 at first), each remembering the size last placed; while placing, + and − change the size and H switches solid and hollow. A placed gear is resized with the scale tool (E): drag across its face for its size (it is replaced by that size on the same axis, keeping its settings, wires and mount, in one undo step; the mirror twin follows) or along its axis for its thickness. Players place one next to another and the placement guide shows where they mesh (grey: the teeth would not touch; green: they mesh). Everything that follows lets a mod add its own — and they mesh with the game's gears and with every other mod's.
For now the game's own gears are hidden from the block palette until a player types /gears in the developer console (/gears off hides them again). They are only hidden: creations with gears load and run, "base": "Gear 16" works, and a mod's gear blocks always appear.
Gears simulate on the Jolt physics engine (Settings → Physics → Physics Engine). On PhysX they are drawn but do not turn, and the game says so once. Nothing a mod does changes that; kinetics.available() tells a server script which it is.
How gears behave
- One module, one grid. The game's gears have 25 mm teeth (module 0.025) and tooth counts that are multiples of 16, so every pitch radius is a whole number of 0.2 m cells: gears of any size mesh when their edges meet on the build grid, and each takes only the cells its teeth reach. Gears only mesh with gears of the same module.
- Gears never turn by themselves. The game's gears have no controls: a gear is bolted to the part it is built on and turns only when that part does — on a servo, a Bearing (wire the Engine into the Bearing, not the gear) or a wheel. On a part nothing turns, it holds still. Gears on different turning parts drive each other through their teeth; a gear on a rotor meshing one on that rotor's own base stops it, and its Jammed channel says so. RPM and Angle read the turn of its part. Gears in older saves set to Own axle keep turning freely on it. A gear with a mechanism of your own (below) defaults to its own axle, where your drive turns it.
- Loads are real. Gears on different parts push on each other through their teeth, and overloaded teeth jump. Gears on axles of their own meshed on one part form one train, which costs the physics what one gear costs — tens of thousands are fine.
- No speed limit. An axle turns at whatever speed its drive and ratios give — hundreds of thousands of rpm — without the physics breaking, and a fast one steers its part like a gyroscope.
- Worms lock. A worm drives its wheel, but the wheel cannot turn the worm back.
A gear block
Add gear to a block definition:
{
"id": "great-wheel",
"name": "Great Wheel 96",
"base": "Cube",
"model": "/models/great-wheel.glb",
"gear": { "kind": "spur", "size": 6 },
"spin": { "meshes": ["Wheel"] }
}With size (1–8: 96 teeth and 1.2 m of pitch radius at size 6) the gear gets exactly the game's geometry for that size: a box (2 × size + 1) cells square and one deep, faces on the cells its rim covers, only those cells occupied (a hollow gear's middle stays free for other blocks), stretching only along its axle, and the game's own teeth drawn when there is no model. "hollow": true adds teeth inside (size 3 and up). With size, leave out the keys it decides (teeth, module, axis, centre, hubs, faceWidth, and the block's size).
From gear the game also gives the block the Gear mechanism: no controls, bolted to its part (above), RPM, Angle and Jammed on wires; for a motor, servo or brake, give the block a mechanism of its own. A gear given teeth instead of a size gets the older shape — hub faces on a half-cell grid, a round footprint, a collider a little smaller than its teeth — and meshes, but off the grid; the mod's log then says "add gear.size for grid placement". Every key below can still be set explicitly.
A block based on one of the game's gears ("base": "Gear Size 3") is a gear already: give it a model and a name and you have a new-looking gear with the same teeth. A gear table then changes only what it names: new teeth that are a grid size (a multiple of 16) make it that size, anything else that reshapes it (another module, axis or box) makes it a plain, off-grid gear. The older names ("Gear 24" …) still work as bases.
gear field | Description |
|---|---|
kind | spur, internal (a ring gear: teeth inside), bevel (45°: two of the same size mesh at a right angle), rack (straight), worm or axle (no teeth; carries the turn along). |
size | A grid gear of the game's family, 1–8: 16 teeth and one cell (0.2 m) of pitch radius a size (above). |
hollow | With size (3–8): teeth inside too, 16 fewer, and its middle open. |
teeth | Tooth count, 6–1024. At the game's module, multiples of 16 are the grid sizes — size gives them the grid geometry. |
module | Tooth size in metres (default 0.025, the game's). The pitch radius is teeth × module ÷ 2. |
faceWidth | Thickness of the teeth along the axle, metres (default 0.18). |
length | Rack, worm or axle length, in cells. |
radius | Worm and axle radius, metres. (For toothed gears it follows from the teeth.) |
starts | Worm threads (default 1): one turn moves the wheel this many teeth. |
axis | The axle, block-local: "+z" (default), "x", [0, 1, 0] … For a rack, its direction of travel. |
centre | The pitch circle's centre, in cells (default the block's centre). Rack: a point on its pitch line where a tooth sits. |
normal | Rack: from its teeth toward the gear. |
reference | The direction tooth 0 points (default "+x"), so the teeth are drawn between the neighbours'. |
apex | Bevel: distance from the pitch circle to the cone's tip, metres (default the radius: a 45° miter). |
hubs | [back, front]: where the hub faces are along the axle, in cells (default [-0.5, 0.5]). |
strength | Tooth force before the teeth jump, newtons (default worked out from size: about 340 kN for the game's). The weaker gear of a pair decides. |
friction | Tooth friction. A worm with 0.15 (its default) cannot be turned back by its wheel. |
Gear models are taken as they are — in metres, about their own origin — rather than fitted to a block and centred like other models, because the teeth must sit exactly on the pitch circle the physics rolls. Model the axle along +Z with tooth 0 centred on +X. modelUnits, fit and centre still override that.
Block shape, faces and spinning parts
These work on any block, gear or not.
| Field | Description |
|---|---|
size | The block's box in cells: 2 or [4, 1, 1]. The model is fitted into it and faces cover it. |
colliderSize, colliderCentre | A collision box different from size, in cells. |
faces | Where other blocks attach: "box" (every side of the box), "hub" (a gear's hubs), "none", or a list of { "at": [x, y, z], "facing": "+x", "size": [w, h], "connect": true, "aero": true } in cells. Left out: a new gear gets hubs, a block with a new size gets its box, others keep their base's. |
spin | Meshes drawn turning with the block's axle: true (all), or { "meshes": ["Wheel"], "axis": "+z", "pivot": [0, 0, 0] } with the model's mesh names and a point on the axle in cells. |
footprint | What counts as overlapping in the editor: "box", or { "shape": "cylinder", "axis": "z", "radius": 6 } (or "ring" with an innerRadius), in cells. Round parts with parallel axes may sit as close as their radii; round parts fit in a ring's hole. |
scalable, minScale, maxScale | Stretching, as a number or [x, y, z] of cells. |
scaleLink | Axes that stretch together, e.g. "xy" to keep a disc round. |
connectableTo | Mechanisms it may be wired to beyond the defaults, e.g. ["Engine"]. |
modelUnits | "cells" or "metres", for a model that is not fitted ("fit": false). |
centre | false keeps the model's own origin instead of centring its bounds. |
A mechanism in data
mechanism gives a block its own settings panel, keys, wires and — on anything that turns — a shaft drive. The engine runs it natively every physics step, exactly like the game's own parts; there is no per-step script.
{
"id": "clockwork", "name": "Clockwork Motor", "base": "Gear 16",
"mechanism": {
"name": "Clockwork",
"settings": [
{ "name": "Spring", "type": "choice", "options": ["Run", "Hold", "Coast"], "default": "Run" },
{ "name": "Speed", "type": "number", "default": 30, "min": 0, "max": 240, "unit": "rpm",
"writable": true, "visibleWhen": { "Spring": "Run" } },
{ "name": "Torque", "type": "number", "default": 150, "min": 0, "max": 2000, "unit": "N·m" },
{ "name": "Wind", "type": "key", "default": "None" }
],
"drive": { "modeSetting": "Spring", "modes": ["motor", "brake", "free"],
"speed": "Speed", "speedUnit": "rpm", "torque": "Torque", "forward": "Wind" },
"channels": [ { "name": "RPM", "source": "rpm" } ]
}
}Settings — up to 32, each { name, type, label?, hint?, section? }:
type | Extra fields |
|---|---|
number | default, min, max, unit, decimals, slider: [from, to] (the slider's span when the allowed range is wider), step, percent |
choice | options (2–16 names), default (a name or an index) |
bool | default |
key | default (a key name like "R", "Space", "LeftShift", or "None"), color |
text | default, maxLength |
Any setting may add "writable": true (numbers and bools: a wire may set it while running) and "visibleWhen": { "Other": value or [values] } (shown only then; choices by option name). section is mode, controls, tuning or options.
drive (only on blocks that turn — a gear, or based on one):
| Field | Description |
|---|---|
mode | A fixed mode: free, motor, servo, brake or none. |
modeSetting, modes | A choice setting that picks the mode, and the mode for each of its options (default: the option names). |
speed, speedUnit | The number setting for motor speed (and servo speed), in rpm (default), deg/s or rad/s. |
torque | The number setting for the most torque, N·m — or a fixed number. |
angle, angleUnit | Servo target setting, in deg (default), rad or turns. Required for a servo mode. |
forward, reverse | Key settings that command it. Wires command it too. |
runWhenUnbound | With no key bound and no wire, a motor runs and a brake holds on its own (default true). |
engines | Wired Engines turn it at their speed and torque (default true). |
A motor turns while commanded; a brake holds while commanded; a servo turns to its angle and holds it.
channels — values it reports on wires, each { name, source, unit?, hint? } where source is speed (in the drive's unit), rpm, angle (degrees, not wrapped), torque, command (-1…1 from keys and wires) or jammed. signal chooses what a wire carries when it names no channel (default rpm). Every number and bool setting is readable on wires as well.
The panel gets the rows a drive needs without declaring them: Toggle Mode and Require Seat when it has keys, Invert when engines may drive it, and Mount and Bearing Friction on a gear.
The mechanism's id is your.mod-id:<id> (default the block's id). Several blocks can share one: declare it on the first and write "mechanism": "clockwork" on the others.
Placement guides
building.placement guides players placing a block type — what the game's gear guide does for gears. The function runs every frame of the drag (client scripts, building permission):
building.placement("clockwork", function(q)
local s = q.suggested -- the game's own guide, for blocks it guides (gears)
if not s or s.state ~= "valid" then return nil end
return { position = s.position, rotation = s.rotation, state = "valid",
label = s.label .. " · clockwork", settings = s.settings, attachTo = s.attachTo }
end)q has position and rotation (where the editor would snap it), snapped, hit (position, normal, block), ray (origin, direction), scale, chosenRotation, creation and — for blocks the game guides — suggested (position, rotation, state, label, settings, attachTo).
Return a table to take over: position + rotation (world), state ("valid" green, "neutral" grey, "invalid" red, "default"), a short label by the cursor, settings the block is placed with, attachTo (a Block), and guides — circles { centre, normal, radius, state or color }, lines { from, to, … }, dots { position, radius, … }, up to 64 each. Without guides of your own the game's are kept. Return nil to keep the game's suggestion, false for no guidance. An error in the guide is logged and the block is left to the editor for a few seconds.
The kinetics module
Gear blocks mesh by themselves wherever players put them. The kinetics module is for everything else: a custom block that turns on an axle, teeth on any block, gears meshed on command. Server scripts; making and driving needs the building.kinetics permission.
building.onPlaced("turntable", function(block)
local shaft = kinetics.shaft(block, { axis = "+y", friction = 2 }) -- it turns about its own Y
local ring = kinetics.gear(block, { shaft = shaft, teeth = 64, axis = "+y" })
shaft:motor(6, 800) -- 6 rpm, at most 800 N·m
end)
kinetics.onTeethJumped(function(mesh, teeth) log.warn("teeth jumped on", mesh.a.block.name) end)| Function | Description |
|---|---|
kinetics.shaft(block, options) | An axle for a block: axis, pivot (cells), friction, damping, inertia, gyroscopic. Not for gear blocks, which have theirs. |
kinetics.shaftOf(block) | The shaft a block turns with — yours, another mod's, or an older own-axle gear's. nil for a game gear on Auto: it is bolted to its part. |
kinetics.gear(block, options) | Teeth on a block, turning with shaft or fixed to its part: kind (circle, line, screw), centre, axis, normal, reference, radius or teeth + module, lead, internal, extent, strength, friction. |
kinetics.gearsOn(block) | The teeth on a block. |
kinetics.mesh(a, b, options) | Meshes two gears (on one creation), wherever they are: strength, friction, engage. |
kinetics.onTeethJumped(fn) | fn(mesh, teeth) when teeth jump. |
kinetics.spin(block), kinetics.rpm(block) | How a block's spinning parts are drawn turned (degrees) and how fast they turn — client or server. A gear bolted to its part has none spinning (the part turns): read its RPM channel. |
kinetics.available(), kinetics.stats() | Whether gears simulate, and counts for profiling. |
Shaft: angle, rpm, torque, jammed, simulated, block, mine; :motor(rpm, torque), :servo(degrees, rpm, torque), :brake(torque), :free(), :setFriction(n, damping), :setInertia(kg·m²), :add(block), :remove(block), :blocks(), :destroy(). Gear: kind, radius, teeth, shaft, block, :meshes(), :setShaft(shaft), :destroy(). GearMesh: a, b, engaged, force, slip, skips, :destroy().
A mod changes only what it made; the game's gears are changed through their blocks' settings. Everything a mod made is removed when it stops. Units: rpm and degrees in scripts, metres for radii, cells for positions on a block.
Saves with mod blocks
A creation records which mods its blocks came from. Loading one shows which mods it was built with and whether each is active. If any is not, Load without mod blocks loads a copy with those blocks left out; the save file itself is never changed, so it loads whole again once the mods are back.