import type { ReactNode } from 'react' import type { Params } from '../engine/types.ts' export type Control = | { kind: 'slider' key: string label: string min: number max: number step?: number /** discrete choices; the slider then moves over their indices */ values?: number[] format?: (v: number) => string } | { kind: 'select' key: string label: string options: { value: string | number; label: string }[] } | { kind: 'toggle'; key: string; label: string } export interface LabSpec { id: string title: string /** one line telling the reader what to watch */ caption?: string /** the fixed part of the MATLAB layer, hidden from the reader */ driver: string /** the editable part: the method itself */ script: string controls: Control[] defaults: Params /** turns the control settings into what params.json should contain */ derive?: (p: Params) => Params /** heavy labs wait for the Run button instead of running on sight */ manual?: boolean /** the editor starts open when the script is the point of the section */ editorOpen?: boolean // eslint-disable-next-line @typescript-eslint/no-explicit-any render: (data: any, params: Params) => ReactNode /** numbers for the status strip beside the timing */ // eslint-disable-next-line @typescript-eslint/no-explicit-any summary?: (data: any, params: Params) => { label: string; value: string }[] } export interface Chapter { id: string /** short name for the sidebar */ nav: string title: string /** one sentence, shown under the title and in the contents */ blurb: string part: Part /** the prose, with lines marking where each lab goes */ text: string labs: LabSpec[] } export const PARTS = ['Introduction', 'Strings', 'Drums', 'Rooms'] as const export type Part = (typeof PARTS)[number]