// Example registry. Sources come from two places: // - curated hand-written scripts (fid/epi/gre) with friendlier comments // - auto-adapted pulseq demoSeq scripts under ./pulseq/*.m, generated by // scripts/gen-examples.mjs (only demos that actually run on numbl) // Metadata (name/category/description) is looked up in CATALOG; run-time // labels come from generated-timings.ts. An id without a CATALOG entry is // skipped, so stale generated files can't leak in unlabeled. import { CATALOG, type Category } from './catalog.ts' import { TIMINGS } from './generated-timings.ts' import fidSource from './fid.m?raw' import epiSource from './epi.m?raw' import greSource from './gre.m?raw' export interface Example { id: string name: string category: Category description: string source: string /** Rough in-browser run time, e.g. "~2 s". */ approx: string /** True for the hand-written curated scripts. */ curated: boolean } const curated: Record = { fid: fidSource, epi: epiSource, gre: greSource, } const generatedModules = import.meta.glob('./pulseq/*.m', { query: '?raw', import: 'default', eager: true, }) as Record const generated: Record = {} for (const [path, source] of Object.entries(generatedModules)) { const id = path.replace(/^\.\/pulseq\//, '').replace(/\.m$/, '') if (!(id in curated)) generated[id] = source } function build(id: string, source: string, curatedFlag: boolean): Example | null { const meta = CATALOG[id] if (!meta) return null return { id, name: meta.name, category: meta.category, description: meta.description, source, approx: TIMINGS[id] ?? '', curated: curatedFlag, } } export const EXAMPLES: Example[] = [ ...Object.entries(curated).map(([id, src]) => build(id, src, true)), ...Object.entries(generated).map(([id, src]) => build(id, src, false)), ].filter((e): e is Example => e !== null) export function findExample(id: string): Example | undefined { return EXAMPLES.find((e) => e.id === id) }