/** * The preset scenes the Play layer offers — each one an ordinary SceneSpec, * nothing a user could not build by hand in the Build tab. A preset is a * starting point, not a mode: picking one loads its spec into the builder, * and everything stays editable from there. */ import type { SceneSpec } from './types.ts'; export interface Preset { key: string; label: string; blurb: string; /** What the excite button says for this scene. */ verb: string; spec: SceneSpec; /** Where the microphone starts, metres. */ mic: { x: number; y: number; z: number }; } export const PRESETS: Preset[] = [ { key: 'dulcimer', label: 'Dulcimer', blurb: 'One plucked string over a rigid box with a sound hole — the scene the dulcimer project hardcodes, here just a preset.', verb: 'Pluck', spec: { objects: [ { id: 's1', type: 'string', size: { L1: 0.6 }, params: {}, place: {}, }, ], body: { type: 'box', params: {} }, }, mic: { x: 0.12, y: 0.08, z: 0.1 }, }, { key: 'drum', label: 'Drum', blurb: 'A struck membrane over a cylindrical shell. The head’s inharmonic modes plus the cavity under it are what make it a drum.', verb: 'Strike', spec: { objects: [ { id: 'm1', type: 'membrane', size: { L1: 0.32, L2: 0.32 }, params: {}, place: {}, }, ], body: { type: 'shell', params: {} }, }, mic: { x: 0.15, y: 0.1, z: 0.12 }, }, { key: 'chime', label: 'Chime', blurb: 'A stiff bar in open air, struck. No tension, so the stiffness sets the partials — at n²·f1, which is the bell-like sound.', verb: 'Strike', spec: { objects: [ { id: 'b1', type: 'bar', size: { L1: 0.3 }, params: {}, place: { oz: 0.05 }, }, ], body: { type: 'none', params: {} }, }, mic: { x: 0.12, y: 0.08, z: 0.1 }, }, { key: 'bare', label: 'Bare string', blurb: 'The control experiment: the same plucked string with no body at all. Compare it to the dulcimer to hear what the box adds.', verb: 'Pluck', spec: { objects: [ { id: 's1', type: 'string', size: { L1: 0.6 }, params: { gair: 1, gbridge: 0 }, place: {}, }, ], body: { type: 'none', params: {} }, }, mic: { x: 0.12, y: 0.08, z: 0.1 }, }, { key: 'duet', label: 'Duet', blurb: 'Two strings a fifth apart over one box, plucked together — the smallest ensemble, and the point of composing scenes.', verb: 'Pluck', spec: { objects: [ { id: 's1', type: 'string', size: { L1: 0.6 }, params: { f0: 294 }, place: { oy: -0.03 }, }, { id: 's2', type: 'string', size: { L1: 0.6 }, params: { f0: 441, pluckpos: 0.3 }, place: { oy: 0.03 }, }, ], body: { type: 'box', params: { boxw: 0.22 } }, }, mic: { x: 0.12, y: 0.08, z: 0.1 }, }, { key: 'kit', label: 'Drum and chime', blurb: 'A membrane over its shell and a bar beside it, struck together — two kinds of physics in one air.', verb: 'Strike', spec: { objects: [ { id: 'm1', type: 'membrane', size: { L1: 0.3, L2: 0.3 }, params: { f0: 100 }, place: {}, }, { id: 'b1', type: 'bar', size: { L1: 0.25 }, params: { f1: 880 }, place: { oy: -0.12, oz: 0.06 }, }, ], body: { type: 'shell', params: { shellr: 0.16 } }, }, mic: { x: 0.18, y: 0.1, z: 0.12 }, }, ]; export const presetByKey = (key: string): Preset | undefined => PRESETS.find((p) => p.key === key); /** Deep-copy a preset's spec so edits do not bleed back into the preset. */ export const cloneSpec = (spec: SceneSpec): SceneSpec => JSON.parse(JSON.stringify(spec)) as SceneSpec;