Make a swinging door
For a kit door in one level entry, use HingedDoor with swingDegrees: pick the right door.
Goal
Walk into a hinged door to push it open. Press F to drive it to 85 degrees, then press F again to close it.
Files you will edit
src/prefabs.tssrc/game.ts
Steps
In the third-person template, append this prefab to
src/prefabs.ts, using its existingprefabimport. It has noDoororInteractabletag, so the template's key-door system will not teleport it. Its default layer meets the hero's existing mask. Keep the slab clear of walls throughout its sweep.tsexport const SwingDoorPrefab = prefab({ name: 'swing-door', body: { shape: 'box', dims: [0.6, 1, 0.08], kind: 'dynamic', mass: 15, layer: { defaultLayer: true }, mask: { player: true, staticGeometry: true }, }, });In
src/game.ts, addphysicsto the existing SDK import (public games import fromgameable), andSwingDoorPrefabto the./prefabsimport. Add this state and system abovedefineGame. The options are reused rather than allocated in the system.tslet swingJoint = 0; let swingOpen = false; const swingMotor = { mode: 'position', target: 0, maxForce: 500 } as const; const swingTarget = { ...swingMotor, target: 0 }; function driveSwingDoor(ctx: GameContext): void { if (!ctx.input.pressed('F')) return; swingOpen = !swingOpen; swingTarget.target = swingOpen ? 85 : 0; physics.setMotor(swingJoint, swingTarget); }Append these statements to the existing
init(ctx)afterpaintTheLevel. The hinge is on the slab's left edge, just above the floor. Motors start off, so walking into the slab pushes it freely until the first F press.tsconst swingDoor = ctx.spawn(SwingDoorPrefab, { x: 0.6, y: 1.1, z: -3 }); tint(swingDoor, DOOR_COLOUR); swingOpen = false; swingJoint = physics.hinge(swingDoor, 0, { anchor: { x: 0, y: 1.1, z: -3 }, axis: { x: 0, y: 1, z: 0 }, minDeg: -90, maxDeg: 90, friction: 1, });Add
driveSwingDoorto the existingsystemsarray afterlocomotionSystem. Positive angles follow the right-hand rule about +Y: the door moves relative to the world (b = 0). Position targets and limits use degrees. The explicit 500 N·m limit exceeds the default 100 N·m; once engaged, the motor holds the requested angle. To restore free pushing, sendmode: 'off'with a target of zero.
Verify
sh
npm run devWalk to the slab at (0.6, 1.1, -3) and push it from either side: it swings but stops at ±90 degrees. Press F: it settles near +85 degrees; press F again: it returns near zero. Temporarily inspect physics.jointValue(swingJoint) in the system to check those angles; the result is degrees, not radians.