fix(manifold): show active output count in drawer

This commit is contained in:
monkey-w1n5t0n 2026-07-25 14:45:04 +02:00
parent f75f683f40
commit 766493fcdc
3 changed files with 21 additions and 12 deletions

View file

@ -122,7 +122,8 @@ double-click exits). `OutputStage.tsx` is the output columns; drag a bar to set
defines `OUTPUT_MODES` = **particles** (default) / midi / osc / cv / synth / editor, each mapping to a defines `OUTPUT_MODES` = **particles** (default) / midi / osc / cv / synth / editor, each mapping to a
`BackendId`. `DEFAULT_OUTPUT_MODE='particles'`. `outputDisplayCount()` is the shared presentation `BackendId`. `DEFAULT_OUTPUT_MODE='particles'`. `outputDisplayCount()` is the shared presentation
boundary for the stage and routing rows: MIDI uses its configured CC count, while backends without boundary for the stage and routing rows: MIDI uses its configured CC count, while backends without
a separate count present the full mode parameter set. This does not reshape the MLP or clear examples. a separate count present the full mode parameter set. The condensed Outputs panel reports this as an
`N outputs` chip. This does not reshape the MLP or clear examples.
- `src/console/output-mode.ts`, `types.ts`, `model.ts` are the shared vocabulary — read these first - `src/console/output-mode.ts`, `types.ts`, `model.ts` are the shared vocabulary — read these first
when touching anything cross-cutting: when touching anything cross-cutting:
- `types.ts`: `Focus`, `OutputMode`, `DrawerKey`, `DrawerDepth`, `FeedbackModeUI`, `SoloMode`, - `types.ts`: `Focus`, `OutputMode`, `DrawerKey`, `DrawerDepth`, `FeedbackModeUI`, `SoloMode`,

View file

@ -624,6 +624,7 @@ function RoutingDrawer(ctx: ConsoleCtx, depth: DrawerDepth) {
<> <>
<div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }}> <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }}>
<Chip tone="var(--accent)">{modeDesc.label}</Chip> <Chip tone="var(--accent)">{modeDesc.label}</Chip>
<Chip>{activeParams.length} output{activeParams.length === 1 ? '' : 's'}</Chip>
<Chip tone="var(--accent)">live {counts.live || 0}</Chip> <Chip tone="var(--accent)">live {counts.live || 0}</Chip>
<Chip tone="var(--accent-2)">fixed {counts.fixed || 0}</Chip> <Chip tone="var(--accent-2)">fixed {counts.fixed || 0}</Chip>
<Chip>off {counts.off || 0}</Chip> <Chip>off {counts.off || 0}</Chip>

View file

@ -11,18 +11,25 @@ declare global {
test('output sliders follow the active backend output count', async ({ page }) => { test('output sliders follow the active backend output count', async ({ page }) => {
await loadProbe(page); await loadProbe(page);
await page.evaluate(() => { // Drive the real UI path: output target → Outputs drawer → expanded MIDI
window.__mf!.setOutputMode('midi'); // config. This deliberately does not use the debug setters; the regression
window.__mf!.setMidiCcCount(3); // covers the same interaction an operator performs.
}); await page.getByTitle(/^Mode:/).click();
await expect(page.getByTestId('output-stage')).toHaveAttribute('data-output-count', '3'); await page.getByRole('button', { name: 'MIDI', exact: true }).click();
await page.getByTitle('Outputs').click();
await page.getByTitle('Expand').click();
await page.getByLabel('CCs').fill('2');
await page.evaluate(() => window.__mf!.setMidiCcCount(7)); // The count remains visible in condensed chrome after leaving the advanced
await expect(page.getByTestId('output-stage')).toHaveAttribute('data-output-count', '7'); // config, and closing the drawer reveals the same number of stage columns.
await page.getByTitle('Condense').click();
await expect(page.getByText('2 outputs', { exact: true })).toBeVisible();
await page.getByTitle('Close').click();
await expect(page.getByTestId('output-stage')).toHaveAttribute('data-output-count', '2');
const fullCount = await page.evaluate(() => { // Backends without a configured count present the full mode output set.
window.__mf!.setOutputMode('osc'); const fullCount = await page.evaluate(() => window.__mf!.paramCount());
return window.__mf!.paramCount(); await page.getByTitle(/^Mode:/).click();
}); await page.getByRole('button', { name: 'OSC', exact: true }).click();
await expect(page.getByTestId('output-stage')).toHaveAttribute('data-output-count', String(fullCount)); await expect(page.getByTestId('output-stage')).toHaveAttribute('data-output-count', String(fullCount));
}); });