SOURCE / PINNED RELEASE
Made of little things.
Mini Samurai
- Release
- a7beb798adbc…
- Author-recorded commit
- 4f97be1515b8…
- License
- LICENSE
- Author’s source reference
- nostr://npub12lm3rxsva8kfempyjkxupt09e02n3fezurkyadyqfejdc5e0r2kscqty6r/wss%3A%2F%2Fgit.napplet.soy%2F/n-3b28f0efc5b
Archive hash verified: 401ec9347ab8f8cd…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
import type * as THREE from 'three';
/**
* World scale: 1 unit ≈ 10 cm. A mini samurai is about 1 unit tall, so a kitchen
* table (75 cm) is 7.5 units high. +Y is up. Rooms sit on the floor at y = 0.
*/
export type RoomId = 'bathroom' | 'bedroom' | 'kitchen' | 'living' | 'dining' | 'garage' | 'house';
/** Axis-aligned solid box. Fighters stand on tops, collide with sides and can hang from top edges. */
export interface Solid {
minX: number;
minY: number;
minZ: number;
maxX: number;
maxY: number;
maxZ: number;
/** False for walls and other surfaces whose top edges should never be grabbed. Default true. */
grab?: boolean;
/** Round or slippery top (a ball): nobody can stand on it, they slide off. */
slide?: boolean;
/** Optional label for debugging and AI ("bed", "chair-seat", ...). */
name?: string;
/** Moves every frame (the toy train): kept out of the AI's map and item placement. */
moving?: boolean;
/** A cylinder standing in its (square) box: collisions, edges and ledges follow the circle. */
round?: boolean;
}
/** A walkable floor rectangle of a multi-room map (a room, the hallway or a doorway). */
export interface Area {
minX: number;
maxX: number;
minZ: number;
maxZ: number;
/** Which room's household items belong here (none for hallways and doorways). */
room?: RoomId;
/** Doorway: walkable, but too small to place things in. */
doorway?: boolean;
}
/** Loop of toy-train track on the floor: square corners in order, each rounded with radius r. */
export interface TrackDef {
points: [number, number][];
r: number;
}
/** A moving machine in a room (built and run by machines.ts). Positions are in room space. */
export type MachineDef =
/** Ceiling fan: blades turning at height y (blade bottom), reaching out to radius r. */
| { kind: 'fan'; x: number; y: number; z: number; r: number; speed: number }
/** Record player: a platter of radius r whose top is at y, turning at speed (radians per second). */
| { kind: 'turntable'; x: number; y: number; z: number; r: number; speed: number }
/** Toaster: two slots along yaw whose top is at y; pops every period seconds. */
| { kind: 'toaster'; x: number; y: number; z: number; yaw: number; period: number }
/**
* Pendulum hanging from a pivot at (x, y, z), swinging across yaw (its front faces yaw):
* the grandfather clock's bob.
*/
| { kind: 'pendulum'; style: 'clock'; x: number; y: number; z: number; yaw: number; length: number; swing: number; period: number };
/** Something round that rolls when it's hit or pushed (a ball, a tin can, a cotton reel). */
export interface RollerDef {
kind: 'ball' | 'can' | 'reel';
x: number;
y: number;
z: number;
}
/** A basin that slowly fills with water (the bath): its floor rectangle and how high the water gets. */
export interface PoolDef {
minX: number;
maxX: number;
minZ: number;
maxZ: number;
/** Height of the basin floor, and the lowest and highest water levels. */
floor: number;
low: number;
high: number;
/** Seconds to fill from low to high (it then drains and fills again). */
fill: number;
/** Where the tap pours in. */
tap: { x: number; y: number; z: number };
}
/** A dripping tap: drips land at (x, z) on the floor and spread into a slippery puddle. */
export interface DripDef {
x: number;
y: number;
z: number;
/** Largest the puddle grows. */
r: number;
}
export interface SpawnPoint {
x: number;
y: number;
z: number;
/** Facing angle in radians around +Y (0 faces +Z). */
facing: number;
}
export interface RoomData {
id: RoomId;
name: string;
/** Root object holding all room meshes; added to the scene by the caller. */
root: THREE.Group;
/** Every solid a fighter can collide with, including floor and walls. */
solids: Solid[];
/** Exactly four fighter spawns: [team A #1, team B #1, team A #2, team B #2]. */
spawns: SpawnPoint[];
/** Places where household items appear at round start (6–10 of them; more in the house). */
itemSpawns: { x: number; y: number; z: number; kinds?: string[] }[];
/** Item ids (from items.ts) that suit this room. */
itemKinds: string[];
/** Playable floor rectangle inside the walls. */
bounds: { minX: number; maxX: number; minZ: number; maxZ: number };
/** Tallest walkable surface height, for camera framing. */
ceiling: number;
/** Walls (meshes) that the camera may hide when they sit between it and the fight. */
cutaway: { mesh: THREE.Object3D; normal: THREE.Vector3; plane?: WallPlane }[];
/** Multi-room maps: where fighters may be (anywhere in `bounds` otherwise). */
areas?: Area[];
/** Toy-train loop, if this map has one. */
track?: TrackDef;
/** Moving machines (fan, record player, toaster, pendulums). */
machines?: MachineDef[];
rollers?: RollerDef[];
/** Wooden crates holding a toy car each (the garage). */
crates?: { x: number; y: number; z: number }[];
pools?: PoolDef[];
drips?: DripDef[];
/** Background colour / fog colour for the room. */
sky: number;
/** Sunlight direction (from the light toward the scene), normalised. */
sunDir: THREE.Vector3;
}
/**
* Where a wall stands, for maps with many rooms: the wall is hidden while it stands
* between the camera and what it looks at. `axis` is the axis the wall faces along
* (its plane is axis = at); it runs from u0 to u1 along the other axis.
*/
export interface WallPlane {
axis: 'x' | 'z';
at: number;
u0: number;
u1: number;
/** How far past its ends a sight line may cross and still hide it (7 by default). */
pad?: number;
}
export type WeaponStyle = 'katana' | 'slash' | 'stab' | 'blunt';
export interface WeaponDef {
id: string;
name: string;
style: WeaponStyle;
/** Distance from the grip point (origin) to the striking tip, in units. */
length: number;
/** Damage multiplier relative to the katana (1). */
damage: number;
/** Attack speed multiplier relative to the katana (1); heavier items are below 1. */
speed: number;
/** Knockback multiplier. */
knockback: number;
/** Hits before it breaks. The katana never breaks (Infinity). */
durability: number;
/** Held with both hands (long or heavy items). */
twoHanded: boolean;
/** Two sticks on a cord (nunchaku): the free stick (mesh named "flail") swings loose and does the hitting. */
flail?: boolean;
/**
* Builds the low-poly mesh. Convention: origin = where the fist grips,
* the striking part extends along +Y to y = length, a short handle end may
* extend to negative Y. Flat blades are thin along X with the cutting edge facing +Z.
*/
build(): THREE.Object3D;
}
/** A household object that is lifted over the head and thrown (cups, bottles, soap, a big wrench...). */
export interface ThrowDef {
id: string;
name: string;
/** Damage on a direct hit (fighters have 100 health; a katana slash does about 7). */
damage: number;
/** Knockback speed on hit; 5 or more knocks the target down. */
knock: number;
/** 0.5 (feather-light) .. 1.5 (very heavy): slows the carrier and the throw. */
weight: number;
/** Shatters on impact (glass, ceramic, eggs) instead of bouncing and staying in the room. */
breaks: boolean;
/** A cube (a die) that comes to rest on whichever face it lands on, instead of standing upright. */
anyFace?: boolean;
/** Round (a marble): keeps rolling along the floor after it lands. */
rolls?: boolean;
/** Flicked rather than thrown (a rubber band): this fast, in a nearly straight line. */
flick?: number;
/** Weapons that spill out when it breaks (a crayon box). */
burst?: string[];
/** Leaves a slippery puddle this big where it bursts (a water balloon). */
splash?: number;
/** A pick-up that does something when grabbed instead of being carried. */
power?: 'sugar' | 'thimble' | 'button';
/** Height and horizontal radius of the object in units (1 unit ≈ 10 cm). */
height: number;
radius: number;
/** Colours used for the shards / splash when it breaks. */
chips: number[];
/**
* Builds the low-poly mesh. Convention: origin at the centre of the object's
* BOTTOM face, standing upright along +Y up to y = height, footprint within radius.
*/
build(): import('three').Object3D;
}
