memlnaut-nisps/playground/src/modes/ElysiamorfMode.tsx
w1n5t0n f916344c9b feat(playground/modes): all 9 mode bindings + /modes route (meml-yt7)
Stream 9 (part 2/2) — concrete mode TSX components + routing.

Each firmware mode pairs the generated schema with the appropriate
primary input (XYPad for xy_pad schemas, VirtualJoystick for joystick
schemas) and feeds the runtime's processedOutputs into the shared
SliderBank/OutputDisplay/LossPlot layout. The set:

  - PAFSynthMode (xy_pad, voice spaces)
  - ChannelStripMode (joystick)
  - XIASRIMode (joystick — mic-input wiring deferred to stream 10)
  - VerbFXMode (joystick, voice spaces)
  - MEMLCeliumMode (xy_pad, voice spaces)
  - BreakOrMode (xy_pad)
  - ElysiamorfMode (xy_pad)
  - SoundAnalysisMIDIMode (audio_in fallback to joystick;
      mic capture is a stream-10 task — UI scaffold renders today)
  - C15Mode (browser-only placeholder; bridge not yet ported)

App.tsx adds a /modes route that renders <ModeSwitcher /> + the active
mode's component via Solid <Dynamic />. modes/index.ts exposes the
registry the switcher consumes.
2026-04-29 17:00:56 +03:00

64 lines
1.9 KiB
TypeScript

/**
* ElysiamorfMode — granular / morphing synth (xy_pad input, 40 outputs).
*/
import { Component } from 'solid-js';
import { ModeShell } from './ModeShell';
import { useModeRuntime } from './mode-runtime';
import { XYPad } from '../primitives/XYPad';
import { OutputDisplay } from '../primitives/OutputDisplay';
import { SliderBank } from '../primitives/SliderBank';
import { LossPlot } from '../primitives/LossPlot';
import { paramsToSliderConfig, outputsToSliderValues } from './mode-helpers';
import { ElysiamorfSchema } from './generated/elysiamorf_schema';
export const ElysiamorfMode: Component = () => {
const schema = ElysiamorfSchema;
const runtime = useModeRuntime(schema);
const sliderConfig = paramsToSliderConfig(schema.params);
const sliderValues = () => outputsToSliderValues(runtime.processedOutputs(), schema.params);
return (
<ModeShell
schema={schema}
runtime={runtime}
drawerTitle="Elysiamorf params"
drawerContent={() => (
<SliderBank
title="Live morph params"
sliders={sliderConfig}
values={sliderValues}
onChange={() => {
/* read-only */
}}
/>
)}
primaryInput={() => (
<>
<XYPad
size={280}
ariaLabel="Elysiamorf pad"
onMove={(x, y) => runtime.setInput(x, y)}
position={runtime.pipedInput}
/>
<span style={{ 'font-size': 'var(--fs-xs)', color: 'var(--fg-mute)' }}>
Drag to morph through grain space.
</span>
</>
)}
outputArea={() => (
<>
<OutputDisplay
values={runtime.processedOutputs}
width={360}
height={120}
color="#ffb060"
/>
<LossPlot history={runtime.training.lossHistory} width={360} height={70} />
</>
)}
/>
);
};
export default ElysiamorfMode;