2026-02-21 16:42:42 -05:00
# Item Types
This is behavior-focused documentation for item types and their defaults.
## Shared Item Behavior
- Items are server-authoritative.
- Global per-type fields are injected by the server and are not persisted per-instance:
- `capabilities`
- `useSound`
- `emitSound`
- `useCooldownMs` (from item catalog)
2026-02-21 19:37:08 -05:00
- `emitRange` (spatial range in squares)
- `directional` (directional attenuation enabled)
2026-02-21 16:42:42 -05:00
- Instance fields are persisted in `server/runtime/items.json` .
## `radio_station`
### Defaults
- Title: `radio`
- Params:
- `streamUrl=""`
- `enabled=true`
2026-02-21 22:55:20 -05:00
- `mediaChannel="stereo"`
2026-02-21 22:38:48 -05:00
- `mediaVolume=50`
2026-02-21 22:55:20 -05:00
- `mediaEffect="off"`
- `mediaEffectValue=50`
2026-02-25 00:52:28 -05:00
- `stationName=""` (server-managed, read-only)
- `nowPlaying=""` (server-managed, read-only)
2026-02-21 19:37:08 -05:00
- `facing=0`
2026-02-24 21:24:31 -05:00
- `emitRange=10`
2026-02-21 16:42:42 -05:00
- Global:
- `useSound=none`
- `emitSound=none`
- `useCooldownMs=1000`
2026-02-24 21:24:31 -05:00
- `emitRange=10`
2026-02-21 19:37:08 -05:00
- `directional=true`
2026-02-21 16:42:42 -05:00
### Use
- `use` toggles `enabled` on/off and broadcasts chat status.
2026-02-25 01:11:47 -05:00
- `secondary use` reports now-playing metadata (`Playing <song> from <station>` ), or `<title> is off` when disabled.
2026-02-21 16:42:42 -05:00
### Validation
2026-02-21 22:55:20 -05:00
- `mediaChannel` : `stereo | mono | left | right`
2026-02-21 22:38:48 -05:00
- `mediaVolume` : integer `0..100`
2026-02-21 22:55:20 -05:00
- `mediaEffect` : `reverb | echo | flanger | high_pass | low_pass | off`
- `mediaEffectValue` : number `0..100` with `0.1` precision
2026-02-25 00:52:28 -05:00
- Visible only when `mediaEffect != off` (`visibleWhen: {"mediaEffect": "!off"}` )
2026-02-24 03:00:30 -05:00
- `facing` : number `0..360` with step `1`
2026-02-21 20:31:34 -05:00
- `emitRange` : integer `5..20`
2026-02-25 00:52:28 -05:00
- `stationName` / `nowPlaying` : server-fetched metadata fields; not editable by clients.
2026-02-21 16:42:42 -05:00
## `dice`
### Defaults
- Title: `Dice`
- Params:
- `sides=6`
- `number=2`
- Global:
- `useSound=sounds/roll.ogg`
- `emitSound=none`
- `useCooldownMs=1000`
2026-02-21 19:37:08 -05:00
- `emitRange=15`
- `directional=false`
2026-02-21 16:42:42 -05:00
### Use
- Rolls `number` dice with `sides` sides and reports values + total.
### Validation
- `sides` : integer `1..100`
- `number` : integer `1..100`
## `wheel`
### Defaults
- Title: `wheel`
- Params:
- `spaces="yes, no"`
- Global:
- `useSound=sounds/spin.ogg`
- `emitSound=none`
- `useCooldownMs=4000`
2026-02-21 19:37:08 -05:00
- `emitRange=15`
- `directional=false`
2026-02-21 16:42:42 -05:00
### Use
- Announces spin immediately.
- Result is sent after delay.
### Validation
- `spaces` : comma-delimited values
- At least 1 entry
- Max 100 entries
- Max 80 chars per entry
## `clock`
### Defaults
- Title: `clock`
- Params:
- `timeZone="America/Detroit"`
- `use24Hour=false`
2026-02-27 01:05:23 -05:00
- `topOfHourAnnounce=true`
2026-02-27 02:06:51 -05:00
- `alarmEnabled=false`
- `alarmTime=""`
2026-02-21 16:42:42 -05:00
- Global:
- `useSound=none`
- `emitSound=sounds/clock.ogg`
- `useCooldownMs=1000`
2026-02-21 19:37:08 -05:00
- `emitRange=10`
- `directional=false`
2026-02-21 16:42:42 -05:00
### Use
2026-02-27 01:05:23 -05:00
- Broadcasts a spoken EL640-style time announcement as spatial audio from the clock position.
- No text chat line is emitted for clock `use` .
2026-02-21 16:42:42 -05:00
### Validation
- `timeZone` : one of `CLOCK_TIME_ZONE_OPTIONS` in `server/app/item_catalog.py`
- `use24Hour` : boolean or on/off style input
2026-02-27 01:05:23 -05:00
- `topOfHourAnnounce` : boolean or on/off style input
2026-02-27 02:06:51 -05:00
- `alarmEnabled` : boolean or on/off style input
- `alarmTime` : `HH:MM` when `use24Hour=true` , otherwise `H:MM AM/PM`
2026-02-27 01:05:23 -05:00
### Audio
- Spoken clock assets live under `client/public/sounds/clock/el640/` .
- Top-of-hour routine (when enabled) uses `hour1.ogg` + time phrase + `hour2.ogg` .
2026-02-27 02:06:51 -05:00
- Alarm routine (when enabled and time matches) uses `announcement.ogg` + time phrase + `alarm.ogg` .
2026-02-21 18:31:25 -05:00
2026-02-21 22:20:15 -05:00
## `widget`
### Defaults
- Title: `widget`
- Params:
- `enabled=true`
- `directional=false`
- `facing=0`
- `emitRange=15`
2026-02-21 22:38:48 -05:00
- `emitVolume=100`
2026-02-21 23:10:17 -05:00
- `emitSoundSpeed=50`
2026-02-21 23:17:18 -05:00
- `emitSoundTempo=50`
2026-02-21 22:55:20 -05:00
- `emitEffect="off"`
- `emitEffectValue=50`
2026-02-21 22:20:15 -05:00
- `useSound=""`
- `emitSound=""`
- Global:
- `useSound=none`
- `emitSound=none`
- `useCooldownMs=1000`
- `emitRange=15`
- `directional=false`
2026-02-21 23:17:18 -05:00
- `emitSoundSpeed=50`
- `emitSoundTempo=50`
2026-02-21 22:20:15 -05:00
### Use
- `use` toggles `enabled` on/off and plays `useSound` when configured.
### Validation
- `enabled` : boolean or on/off style input
- `directional` : boolean or on/off style input
2026-02-24 03:00:30 -05:00
- `facing` : number `0..360` with step `1`
2026-02-21 22:20:15 -05:00
- `emitRange` : integer `1..20`
2026-02-21 22:38:48 -05:00
- `emitVolume` : integer `0..100`
2026-02-21 23:17:18 -05:00
- `emitSoundSpeed` : integer `0..100` (`0=0.5x` , `50=1.0x` , `100=2.0x` ) for speed/pitch
- `emitSoundTempo` : integer `0..100` (`0=0.5x` , `50=1.0x` , `100=2.0x` ) for tempo
2026-02-21 22:55:20 -05:00
- `emitEffect` : `reverb | echo | flanger | high_pass | low_pass | off`
- `emitEffectValue` : number `0..100` with `0.1` precision
2026-02-21 22:20:15 -05:00
- `useSound` : empty, filename (assumed under `sounds/` ), or full URL
- `emitSound` : empty, filename (assumed under `sounds/` ), or full URL
2026-02-22 23:42:17 -05:00
## `piano`
### Defaults
- Title: `piano`
- Params:
- `instrument="piano"`
2026-02-23 00:22:36 -05:00
- `voiceMode="poly"`
- `octave=0`
2026-02-22 23:42:17 -05:00
- `attack=15`
- `decay=45`
2026-02-23 00:05:01 -05:00
- `release=35`
- `brightness=55`
2026-02-22 23:42:17 -05:00
- `emitRange=15`
- Global:
- `useSound=none`
- `emitSound=none`
- `useCooldownMs=1000`
- `emitRange=15`
- `directional=false`
### Use
- Announces that the user begins playing the piano (client enters piano key mode).
2026-02-23 00:36:36 -05:00
- Piano mode controls include `,` to start/stop recording (max 30s) and `.` to play saved recording.
- Recordings are stored on the item (server-authoritative), so nearby users hear playback.
2026-02-22 23:42:17 -05:00
### Validation
2026-02-23 00:22:36 -05:00
- `instrument` : `piano | electric_piano | guitar | organ | bass | violin | synth_lead | brass | nintendo | drum_kit`
- `voiceMode` : `poly | mono`
- `octave` : integer `-2..2`
2026-02-22 23:42:17 -05:00
- `attack` : integer `0..100`
- `decay` : integer `0..100`
2026-02-23 00:05:01 -05:00
- `release` : integer `0..100`
- `brightness` : integer `0..100`
2026-02-22 23:42:17 -05:00
- `emitRange` : integer `5..20`
2026-02-23 00:22:36 -05:00
- Instrument changes reset `voiceMode` /`octave` /`attack` /`decay` /`release` /`brightness` to instrument defaults.
2026-02-22 23:42:17 -05:00
2026-02-24 02:49:17 -05:00
## Adding A New Item Type (Plugin Discovery)
2026-02-21 18:31:25 -05:00
2026-02-24 02:49:17 -05:00
Server is the source of truth for item type definitions and metadata. The client consumes server `welcome.uiDefinitions` and only provides UX/runtime behavior.
2026-02-21 18:57:02 -05:00
For a full copy/paste example with plain-English explanation, see `docs/item-type-template.md` .
2026-02-21 18:31:25 -05:00
2026-02-24 03:08:30 -05:00
1. Server item package: add a new folder under `server/app/items/types/<item_type>/` with:
- `definition.py` (defaults/capabilities/metadata/options)
- `validator.py` (`validate_update` )
- `actions.py` (`use_item` )
2026-02-24 02:49:17 -05:00
2. Server plugin: add `server/app/items/types/<item_type>/plugin.py` exporting `ITEM_TYPE_PLUGIN` with:
- `type`
- `order`
- `module`
The server auto-discovers plugins at boot, so no central registry edit is needed.
2026-02-24 18:56:42 -05:00
3. Server/client protocol/state models are now string-based for item type ids; for generic types no enum/union list updates are required.
2026-02-24 03:00:30 -05:00
5. Client runtime behavior: add `client/src/items/types/<item_type>/behavior.ts` only if custom client runtime is needed (for example piano mode).
2026-02-24 02:49:17 -05:00
6. Tests: add or update server tests under `server/tests/` for use/update validation, unknown-key stripping, and `uiDefinitions` completeness.
2026-02-21 18:31:25 -05:00
### Example Shape
A minimal new item type usually needs:
- Catalog defaults:
- `default_title`
- `default_params`
- `use_sound` / `emit_sound`
- `use_cooldown_ms`
- Handler behavior:
- validate params on update
- build self/others use messages
- optionally return delayed result text