From 3d56206d3c80ef909c59832f6e1615860629b5a5 Mon Sep 17 00:00:00 2001 From: daharoni Date: Tue, 21 Apr 2026 21:25:03 -0700 Subject: [PATCH] fix(catune): repair tutorial highlighting after Peak/FWHM migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 01-basics, 02-workflow, and 03-advanced tutorials still targeted `[data-tutorial="slider-decay"]` and `[data-tutorial="slider-rise"]`, which no longer exist — the kernel parameterization was migrated from tau_rise/tau_decay to Peak/FWHM some time ago. driver.js found no matching element, so the highlight either landed nowhere or fell back to something nearby, depending on the step. One selector was also broken by omission: `[data-tutorial="resize-handle"]` never had a matching attribute anywhere — the Card component's resize handle div was unlabeled. This commit: - Renames selectors in tutorial content: `slider-decay` → `slider-fwhm`, `slider-rise` → `slider-peak`. - Adds `data-tutorial="resize-handle"` to the Card resize handle in `packages/ui/src/Card.tsx`. - Updates step titles, body text, and section comments that still described τ_rise / τ_decay semantics so the popover narrative matches the slider it's highlighting. Mapping used: Decay Time → FWHM (event width) Rise Time → Peak Time Advice about tuning order, parameter coupling, and artifact causes is rewritten accordingly. The underlying kernel math (exponentials, τ_rise/τ_decay) is still discussed where appropriate — the 05-theory tutorial and the community scatter plot still refer to τ values directly, so those remain unchanged. - Fixes a stale JSDoc example in `packages/tutorials/src/types.ts`. Cross-checked every selector referenced by tutorial content against live `data-tutorial=` attributes in apps/catune/src and packages/*/src — no unmatched selectors remain. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/lib/tutorial/content/01-basics.ts | 20 ++++++++--------- .../src/lib/tutorial/content/02-workflow.ts | 22 +++++++++---------- .../src/lib/tutorial/content/03-advanced.ts | 10 ++++----- packages/tutorials/src/types.ts | 2 +- packages/ui/src/Card.tsx | 8 ++++++- 5 files changed, 34 insertions(+), 28 deletions(-) diff --git a/apps/catune/src/lib/tutorial/content/01-basics.ts b/apps/catune/src/lib/tutorial/content/01-basics.ts index 74ec22b6..e66e719c 100644 --- a/apps/catune/src/lib/tutorial/content/01-basics.ts +++ b/apps/catune/src/lib/tutorial/content/01-basics.ts @@ -64,21 +64,21 @@ export const basicsTutorial: Tutorial = { 'Use the +/\u2212 buttons to adjust the number of grid columns (1\u20136). Fewer columns means larger cards for detailed inspection; more columns lets you compare many cells at once.', side: 'bottom', }, - // Step 7: Decay slider (+ kernel shape info absorbed from former kernel display step) + // Step 7: FWHM slider (+ kernel shape info absorbed from former kernel display step) { - element: '[data-tutorial="slider-decay"]', - title: 'Decay Time (tau_decay)', + element: '[data-tutorial="slider-fwhm"]', + title: 'FWHM (Event Width)', description: - 'The most important parameter \u2014 start here. Controls how quickly calcium decays after a neural event. Too short: the solver places extra activity during the decay phase to explain lingering signal (overfitting). Too long: fit is sluggish and misses fast events. Deconvolved activity should primarily appear during the rise, not spread across the whole decay.

' + - 'The kernel display shows the resulting template \u2014 it should match what a real calcium transient looks like for your indicator. Its peak time and half-decay time are annotated.', + 'The most important parameter \u2014 start here. FWHM (full width at half-max) controls the overall duration of each calcium event. Too narrow: the solver places extra activity to explain lingering signal (overfitting). Too wide: fit is sluggish and misses fast events. Deconvolved activity should primarily appear during the rise, not spread across the whole event.

' + + 'The kernel display shows the resulting template \u2014 it should match what a real calcium transient looks like for your indicator. Its peak time and FWHM are annotated.', side: 'right', }, - // Step 8: Rise slider + // Step 8: Peak slider { - element: '[data-tutorial="slider-rise"]', - title: 'Rise Time (tau_rise)', + element: '[data-tutorial="slider-peak"]', + title: 'Peak Time', description: - 'Controls how quickly calcium rises at event onset. Usually much shorter than decay. Fine-tune after decay is set. Note: changing rise slightly changes optimal decay \u2014 they\u2019re coupled, so re-check decay after adjusting rise.', + 'Controls how quickly calcium rises to its peak after event onset. Usually much shorter than FWHM. Fine-tune after FWHM is set. Note: changing Peak slightly changes optimal FWHM \u2014 they\u2019re coupled, so re-check FWHM after adjusting Peak.', side: 'right', }, // Step 9: Lambda slider @@ -86,7 +86,7 @@ export const basicsTutorial: Tutorial = { element: '[data-tutorial="slider-lambda"]', title: 'Sparsity Penalty (lambda)', description: - 'Controls event count. Start low and increase until noise artifacts disappear from the green trace without losing real events. A value of 1 is a good starting point. The green deconvolved trace should show clean, sharp peaks at real events with a quiet baseline between them. If the reconvolved fit peak starts decreasing away from the raw trace as you increase lambda, your sparsity is too high. Prefer adjusting decay time over relying on high sparsity to control overfitting. Increasing decay can help reduce dense deconvolved activity under big fluorescence events. Most cells will respond well to small sparsity values, but a small percentage of cells may be too noisy for reliable deconvolution \u2014 don\u2019t overfit noisy cells, focus on the average-looking cell.', + 'Controls event count. Start low and increase until noise artifacts disappear from the green trace without losing real events. A value of 1 is a good starting point. The green deconvolved trace should show clean, sharp peaks at real events with a quiet baseline between them. If the reconvolved fit peak starts decreasing away from the raw trace as you increase lambda, your sparsity is too high. Prefer adjusting FWHM over relying on high sparsity to control overfitting. Increasing FWHM can help reduce dense deconvolved activity under big fluorescence events. Most cells will respond well to small sparsity values, but a small percentage of cells may be too noisy for reliable deconvolution \u2014 don\u2019t overfit noisy cells, focus on the average-looking cell.', side: 'right', }, // Step 10: Good vs bad fit diff --git a/apps/catune/src/lib/tutorial/content/02-workflow.ts b/apps/catune/src/lib/tutorial/content/02-workflow.ts index f0de3e38..bfdb0ec4 100644 --- a/apps/catune/src/lib/tutorial/content/02-workflow.ts +++ b/apps/catune/src/lib/tutorial/content/02-workflow.ts @@ -26,12 +26,12 @@ export const workflowTutorial: Tutorial = { 'Use \u201CTop Active\u201D mode to find cells with strong activity. Look for a cell with clear, well-separated peaks in the raw trace. Avoid cells dominated by noise or slow baseline drift \u2014 a cell with a few clean events is ideal for initial tuning. Click a card below to switch cells.', side: 'top', }, - // Step 3: Tune decay time (interactive) + // Step 3: Tune FWHM (interactive) { - element: '[data-tutorial="slider-decay"]', - title: 'Step 2: Tune Decay Time', + element: '[data-tutorial="slider-fwhm"]', + title: 'Step 2: Tune FWHM', description: - 'Decay has the biggest visual impact. Find clean, small-amplitude calcium events first. Drag the slider until the fit\u2019s falling edge matches the filtered trace\u2019s falling edge after each peak. Try it now.', + 'FWHM has the biggest visual impact. Find clean, small-amplitude calcium events first. Drag the slider until the fit\u2019s falling edge matches the filtered trace\u2019s falling edge after each peak. Try it now.', side: 'right', waitForAction: 'slider-change', disableActiveInteraction: false, @@ -41,7 +41,7 @@ export const workflowTutorial: Tutorial = { element: '[data-tutorial="card-grid"]', title: 'Step 3: Check Fit & Residuals', description: - 'Look at how the orange fit line follows the blue raw trace after peaks. The tails should line up. If the fit drops too fast, increase decay. If it lingers too long, decrease decay.

' + + 'Look at how the orange fit line follows the blue raw trace after peaks. The tails should line up. If the fit drops too fast, increase FWHM. If it lingers too long, decrease FWHM.

' + 'Then look at the red residual trace at the bottom. Residuals should resemble the noise characteristics of your recording. Near-zero residuals = overfitting. Visible transient shapes in residuals = underfitting. Good residuals are flat noise with no structure.', side: 'bottom', popoverClass: 'driver-popover--wide', @@ -51,7 +51,7 @@ export const workflowTutorial: Tutorial = { element: '[data-tutorial="noise-filter"]', title: 'Step 3b: Consider Noise Filtering', description: - 'Noise leads to deconvolution artifacts. Enable the Noise Filter to apply a bandpass filter derived from your kernel parameters. Filtering is conservative \u2014 it removes high-frequency noise without changing rise time dynamics. Toggle it on to try.', + 'Noise leads to deconvolution artifacts. Enable the Noise Filter to apply a bandpass filter derived from your kernel parameters. Filtering is conservative \u2014 it removes high-frequency noise without changing onset kinetics. Toggle it on to try.', side: 'right', waitForAction: 'filter-toggle', disableActiveInteraction: false, @@ -72,12 +72,12 @@ export const workflowTutorial: Tutorial = { 'The power spectral density shows your data\u2019s frequency content. When Noise Filter is on, dashed lines mark the bandpass cutoffs (HP and LP). The passband should preserve your calcium signal frequencies while rejecting noise.', side: 'left', }, - // Step 8: Fine-tune rise time (interactive) + // Step 8: Fine-tune Peak time (interactive) { - element: '[data-tutorial="slider-rise"]', - title: 'Step 4: Fine-Tune Rise Time', + element: '[data-tutorial="slider-peak"]', + title: 'Step 4: Fine-Tune Peak Time', description: - 'Now adjust the rise time. This is subtle \u2014 it affects the onset of each event. Watch the leading edge of peaks in the fit. Drag to adjust.', + 'Now adjust the Peak time. This is subtle \u2014 it affects how quickly each event reaches its peak. Watch the leading edge of peaks in the fit. Drag to adjust.', side: 'right', waitForAction: 'slider-change', disableActiveInteraction: false, @@ -87,7 +87,7 @@ export const workflowTutorial: Tutorial = { element: '[data-tutorial="card-grid"]', title: 'Check Rise Slopes', description: - 'Zoom into a peak onset. The orange fit should match the blue trace\u2019s upward slope. If the fit rises too slowly, decrease rise time. If it overshoots, increase it slightly. Note: changing rise time may slightly affect the optimal decay \u2014 re-check.', + 'Zoom into a peak onset. The orange fit should match the blue trace\u2019s upward slope. If the fit rises too slowly, decrease Peak time. If it overshoots, increase it slightly. Note: changing Peak time may slightly affect the optimal FWHM \u2014 re-check.', side: 'bottom', }, // Step 10: Add sparsity (interactive) diff --git a/apps/catune/src/lib/tutorial/content/03-advanced.ts b/apps/catune/src/lib/tutorial/content/03-advanced.ts index c0f310cc..64976a43 100644 --- a/apps/catune/src/lib/tutorial/content/03-advanced.ts +++ b/apps/catune/src/lib/tutorial/content/03-advanced.ts @@ -23,7 +23,7 @@ export const advancedTutorial: Tutorial = { element: '[data-tutorial="card-grid"]', title: 'Residual Pattern Analysis', description: - 'The red residual trace reveals model mismatches. Systematic positive bumps after peaks: decay too short. Negative dips before peaks: rise too long. Low-frequency waves: residual baseline drift (the automatic baseline subtraction handles most drift, but very slow trends may remain). Residuals should resemble noise. Near-zero residuals = overfitting. Visible transient shapes = underfitting.', + 'The red residual trace reveals model mismatches. Systematic positive bumps after peaks: FWHM too narrow. Negative dips before peaks: Peak time too long. Low-frequency waves: residual baseline drift (the automatic baseline subtraction handles most drift, but very slow trends may remain). Residuals should resemble noise. Near-zero residuals = overfitting. Visible transient shapes = underfitting.', side: 'bottom', }, // Step 3: Parameter coupling @@ -31,7 +31,7 @@ export const advancedTutorial: Tutorial = { element: '[data-tutorial="param-panel"]', title: 'Parameter Coupling', description: - 'Rise and decay times interact. After adjusting decay, always re-check rise. With longer decay, the model explains more variance, so you may need less sparsity. Tune in order: decay \u2192 rise \u2192 lambda.', + 'Peak and FWHM interact. After adjusting FWHM, always re-check Peak. With a larger FWHM, the model explains more variance, so you may need less sparsity. Tune in order: FWHM \u2192 Peak \u2192 lambda.', side: 'left', }, // Step 4: Indicator-specific guidance @@ -48,7 +48,7 @@ export const advancedTutorial: Tutorial = { title: 'Artifacts & Challenging Signals', description: 'Common artifacts that affect fitting: Motion artifacts: sharp, symmetric deflections (not calcium-shaped). Photobleaching: slow downward baseline trend (largely handled by the automatic rolling-percentile baseline subtraction, but extreme cases may still affect results). Neuropil contamination: broad, slow signals mixed with sharp events. Motion artifacts cannot be fixed by parameter tuning \u2014 they require preprocessing. Photobleaching and neuropil contamination are largely handled by CaTune\u2019s automatic baseline subtraction.

' + - 'When neurons fire rapidly, calcium events overlap. The model handles this via superposition, but dense firing can make individual events hard to resolve. Under big fluorescence events, try increasing decay time to reduce dense deconvolved activity \u2014 increase as much as possible without making the fit too poor.', + 'When neurons fire rapidly, calcium events overlap. The model handles this via superposition, but dense firing can make individual events hard to resolve. Under big fluorescence events, try increasing FWHM to reduce dense deconvolved activity \u2014 increase as much as possible without making the fit too poor.', side: 'bottom', popoverClass: 'driver-popover--wide', }, @@ -78,7 +78,7 @@ export const advancedTutorial: Tutorial = { }, // Step 9: Sampling rate matters { - element: '[data-tutorial="slider-decay"]', + element: '[data-tutorial="slider-fwhm"]', title: 'When Sampling Rate Matters', description: 'If your sampling rate is low (e.g., 10 Hz), fast dynamics are undersampled and parameters may need to be wider to compensate. If your data was recorded at a different rate than entered, all parameter values will be off. Double-check your sampling rate setting.', @@ -89,7 +89,7 @@ export const advancedTutorial: Tutorial = { element: '[data-tutorial="export-panel"]', title: 'Publication-Quality Parameters', description: - 'For publications, report: rise time, decay time, lambda, sampling rate, and calcium indicator. Include the AR2 coefficients from the export JSON \u2014 these are the mathematically equivalent autoregressive representation used by most analysis pipelines. Always note the CaTune version.', + 'For publications, report: Peak time, FWHM, lambda, sampling rate, and calcium indicator. The export JSON also includes the equivalent tau_rise/tau_decay pair and AR2 coefficients used by most analysis pipelines. Always note the CaTune version.', side: 'top', }, // Step 11: Completion (centered modal, no element) diff --git a/packages/tutorials/src/types.ts b/packages/tutorials/src/types.ts index dd82a916..6877ce03 100644 --- a/packages/tutorials/src/types.ts +++ b/packages/tutorials/src/types.ts @@ -3,7 +3,7 @@ /** A single step in a tutorial tour. */ export interface TutorialStep { - /** CSS selector for the target element (e.g., '[data-tutorial="slider-decay"]'). Omit for centered modal. */ + /** CSS selector for the target element (e.g., '[data-tutorial="slider-fwhm"]'). Omit for centered modal. */ element?: string; /** Popover title text. */ title: string; diff --git a/packages/ui/src/Card.tsx b/packages/ui/src/Card.tsx index ba918fc4..a0a135c7 100644 --- a/packages/ui/src/Card.tsx +++ b/packages/ui/src/Card.tsx @@ -52,7 +52,13 @@ export function Card(props: CardProps) { {...spreadDataAttrs(props)} > {props.children} - {props.resizable &&
} + {props.resizable && ( +
+ )}
); }