Skip to content

Franzi ashlar and testing RGB camera issues in docker#285

Open
Franzili wants to merge 79 commits into
masterfrom
franziAshlar
Open

Franzi ashlar and testing RGB camera issues in docker#285
Franzili wants to merge 79 commits into
masterfrom
franziAshlar

Conversation

@Franzili
Copy link
Copy Markdown
Collaborator

  • Adding handling of RGB images for ashlar stitching
  • Testing fix for RGB camera initialization issues in docker

beniroquai added 30 commits May 1, 2026 18:55
Refactor pixel calibration end-to-end: backend, detector managers, and frontend. Adds a pending-calibration approval flow (getPendingCalibration / applyPendingCalibration / discardPendingCalibration) and switches storage to per-detector calibration entries instead of objective-only keys. Removes the overview/AprilTag calibrators and related stream UI, simplifies PixelCalibrationController initialization so it always loads (even without config), and applies flips/pixel-size to detectors via a new _applyCalibrationToDetector helper. Backend: major controller changes, pending state, config persistence, and removal/archiving of apriltag/overview modules. Detector managers (e.g. HikCam) stop reading flipX/flipY and authoritative pixel-size from setup and default to neutral values so PixelCalibrationController is the single source of truth. Frontend: new API wrappers (get/apply/discard pending), calibrate API updated to use detectorName, PixelCalibrationTab reworked to remove overview stream and add a review/edit/apply UI for pending results. Also adds a large CLAUDE_CODE_INSTRUCTIONS_Pixelcalibration.md with refactor guidance and archives some tests/docs and old requirement files.
Introduce objective-aware pixel calibration throughout frontend and backend. Frontend: expose an Objective selector in pixel calibration tabs, pass objectiveId as a query param to PixelCalibration API calls and respect FastAPI query/body mapping. Backend: migrate PixelCalibrationController to key calibrations by "<detector>::<objective>", support objectiveId on calibrate/apply/get/discard/delete/set operations, and only apply calibrations for the currently selected objective while still recognising legacy detector-only keys. Add getPixelSizeUm API, react to objective changes to re-apply matching calibrations, and store objective metadata with pending/persisted entries. Misc: add overviewCameraName config in setup/ExperimentManager and resolve overview camera in ExperimentController; move pixel size/flip defaults out of camera managers (GXPIPY/Tucsen/Virtual) so PixelCalibrationController is the single source of truth.
Make ashlar stitching pick up pixel size from a parent *_protocol.json (falls back to 1.0 µm if not found) by scanning the parent directory and extracting post_params.pixel_size; pass that value to build_ashlar_stitched. Also switch script to run main() by default instead of the test helper. In PixelCalibrationController, remove the transitive cv2 import and simplify imports from affine_stage_calibration (remove re-export of validate_calibration), plus minor whitespace/usage example cleanups.
Introduce detector-aware pixel calibration endpoints and UI changes. Frontend: add API helpers (getAvailableDetectors, getCalibrationData, setCalibrationData), surface detector dropdowns in PixelCalibrationTab and ManualPixelCalibrationTab, send previewSubsamplingFactor and raw preview coords from manual calibration, and add an editable per-(detector,objective) save UI. Backend: PixelCalibrationController gains getAvailableDetectors, previewSubsamplingFactor handling in manual calibration, richer setCalibrationData response, and JSON sanitization to convert numpy types and replace NaN/Inf with nulls. ObjectiveController now logs a one-time warning when falling back to deprecated static pixelsizes. ArkitektManager gets a device-code hook to handle/display device codes. Also bump NanoImagingPack to 2.1.5 in pyproject.toml and setup.py.
Introduce an Opentrons-compatible labware subsystem and UI integration. Adds a new imswitch/imcontrol/model/labware package (models, loader, manager, selector, generators, schema_v2 and built-in definitions), OME plate metadata writer, and unit tests for labware loading/validation/selection. Frontend: add LabwareSelectionPanel and backend API stubs under frontend/backendapi; update WellSelectorComponent and Redux slices to integrate wellplate selection. Backend: update ExperimentController and related experiment controller modules to expose labware/well-selection functionality. Misc: add Windows launch configuration in .vscode/launch.json, remove PixelCalibration instruction doc and add WellplateOpentrons spec.
Migrate ImSwitch to an Opentrons-style labware layer: add docs (docs/labware_opentrons.md), vendored labware JSON definitions, and update labware generator/models/schema to the new format. Remove the legacy wellplate_layouts module and associated frontend API shims; ExperimentController now forwards to the LabwareManager and exposes compatibility wrappers that return the legacy dict shape. Frontend changes: add confirmation dialogs when switching layouts/labware (to avoid accidental point loss), add per-well sub-position grid generation with an SVG preview, and wire apply/replace behaviour to expand sub-positions. Small controller/fallback tweaks keep backward compatibility while encouraging use of the new endpoints and JSON definitions.
Implements autonomous overview scanning, registration persistence, overlay JPEG storage, a new Overview Scan UI tab, and freehand drawing for region-to-points conversion.

Key changes:
- Added CLAUDE_CODE_INSTRUCTIONS.md with implementation notes and design spec.
- Backend: extended overview registration to persist stagePosition/warp, save/load registration config and overlay JPEGs; added endpoints in ExperimentController for running autonomous scans, getting/updating registration config, and serving overlay images.
- Frontend: new OverviewScanTab component and API wrappers (apiGetOverviewRegistrationConfigData, apiUpdateOverviewRegistrationConfig, apiRunAutonomousOverviewScan, apiGetOverviewOverlayImage); moved overlay controls into the new tab and added tabbed UI in WellSelectorComponent.
- Freehand drawing: introduced FREEHAND_DRAW mode in WellSelectorCanvas (drawing, throttling, polygon fill), added generateFreehandScanPositions and clearFreehand exposed via ref, and added convert button in WellSelectorComponent to create experiment points from the polygon.
- State: updated OverviewRegistrationSlice to hold registrationConfig, autonomous scan state and progress, and new reducers used by the tab.

Files added/modified include frontend components (OverviewScanTab, WellSelectorCanvas, WellSelectorComponent, OverviewRegistrationWizard), frontend backendapi wrappers, state slice updates, and backend overview_registration/ExperimentController updates to support persistence and autonomous operation.
Persist overview-camera registration configs into the setup file and load them on startup so registrations survive process restarts. ExperimentController: import config tools, load persisted registrations at init, persist registrations after register/save operations, and add helpers for setup keying. Add overviewRegistration field to SetupInfo. Frontend: expose Overview Scan tab in the main Axon UI, remove the separate tab from WellSelector, and adjust OverviewRegistrationWizard to start the MJPEG stream as soon as the wizard opens. Add areaId/groupId/wellId metadata to points (freehand and well sub-position flows) so related tiles can be grouped by downstream writers, and surface these groups in a new PerWellPointsOverview component. Also persist overview overlay preferences to localStorage and rename/refactor a labware layout helper for clarity.
Add editable objective metadata and related state/handlers, plus various UI and status improvements. Key changes:
- Add new API: apiObjectiveControllerSetObjectiveParameters to set objective metadata on the backend.
- Import and wire the new API in ObjectiveController; add per-slot editable metadata fields, a save handler (handleSaveObjectiveMeta) and UI for name/NA/magnification/pixelsize.
- Populate new objective metadata in Redux via fetchObjectiveControllerGetStatus and add corresponding actions/state in ObjectiveSlice (availableObjectivesNames, availableObjectiveMagnifications, availableObjectiveNAs, availableObjectivePixelSizes).
- Small behavior tweaks: make skipZ default to false in apiObjectiveControllerMoveToObjective; remove an early return in the move handler so flow continues after the positions check (previous return commented out).
- UI/label improvements: rename X0/X1/Z0/Z1 labels to more descriptive Position/Focus 1/2 and adjust related button labels/placeholders.
- Fix FRAMESettingsController tab indices (shift TestHoming/ObjectiveController tabs) and add polling in WizardStep4 so Z updates while user adjusts focus.

These changes enable editing/saving objective parameters from the UI, improve clarity of objective/position labels, and ensure objective metadata is synchronized into application state.
Frontend: Refactor detector parameter fetching to a useCallback and add polling while auto-exposure is active; show a warning Alert when mode is auto. In the StreamControlOverlay add detector discovery, a detector selector (when multiple detectors present), include the selected detector_name in stream parameter payloads, and update labels/tooltips to use RAW (16-bit) wording.

Backend: Add per-detector stream parameter storage (_perDetectorStreamParams). setStreamParams now accepts an optional detectorName and stores per-detector overrides. getStreamParams accepts detectorName (defaults to the first available detector) and merges per-detector overrides into the response. These changes enable selecting and persisting stream settings per detector.
Fetch detector exposure/gain on mount and add a button to apply current camera settings (frontend/src/axon/ExperimentComponent.js). Add z_speed to the experiment model and defaults (models.py, ExperimentSlice.js), expose setZSpeed in the Redux slice, and wire a Z Speed selector into the tiling UI (TilingDimension.js). Improve FocusMap controls to disable/annotate compute buttons in manual-map mode (FocusMapDimension.js). Simplify stream overlay UI by renaming RAW -> Binary, removing detector-name fetching/selector and excluding detector_name from stream requests, and adjust related labels (StreamControlOverlay.js). Server-side ExperimentController now respects z_speed when setting Z motion speed and tightens laser-enable logic to handle falsy values safely (ExperimentController.py). These changes align UI defaults with hardware settings and add explicit Z speed handling across model, controller, and UI.
Replace legacy PixelCalibrationController overview stream usage with LiveViewController endpoints. Components (OverviewRegistrationWizard, SetLasersTab, TestHomingTab) now build MJPEG URLs using /LiveViewController/mjpeg_stream?detectorName=ObservationCamera and call apiLiveViewControllerStartLiveView / apiLiveViewControllerStopLiveView to start/stop streams (subsampling_factor: 1). apiPixelCalibrationControllerOverviewStream was updated to start/stop the ObservationCamera via LiveViewController. Also include stream lifecycle handling in the wizard (start on open, stop on close) and small UI changes in FocusMapDimension (removed disabled on manual measure button and updated button labels).
Switch FRAMESettings tabs to reuse the central WebSocket live stream instead of creating per-component MJPEG endpoints. Added LiveStreamSlice and LiveViewSlice selectors and use apiLiveViewControllerStartLiveView / apiLiveViewControllerStopLiveView to switch the active detector to ObservationCamera (jpeg, 1x subsampling), and restore the previously active detector/protocol when stopping. Replaced component-local MJPEG URLs and img refs with the shared base64 image from liveStreamState.liveViewImage and updated UI to show "Waiting for image..." while active but no image yet. Changes applied to ObjectiveControllerTab, SetLasersTab and TestHomingTab, and include small state/prop cleanup (prevDetectorRef / prevProtocolRef) and error/status messaging updates.
Expose configurable Move Camera speeds and wire them through the UI and state. Added moveCameraSpeedXY and moveCameraSpeedZ to the well selector slice with defaults (20000 µm/s and 1000 µm/s) and validation (parseFloat fallback to defaults). Created actions and handlers to update these values from the component. The WellSelectorComponent now shows XY/Z speed inputs when mode === MOVE_CAMERA and dispatches changes. WellSelectorCanvas uses moveCameraSpeedXY when issuing X/Y positioner move calls. This enables users to adjust camera movement speeds from the UI and persists values in the slice.
Move OverviewRegistrationWizard import and mounting from WellSelectorComponent to AxonTabComponent so the wizard is always available regardless of which tab is active. Remove the redundant import/instance from WellSelectorComponent. Adjust TestHomingTab layout/styles: switch from minHeight to a fixed 500px height, add overflow:hidden, and constrain the live preview image with maxHeight, objectFit: 'contain', and display:block to keep the image scaled and centered without overflow.
Introduce a raster-based stage-center calibration workflow and per-slot recapture support.

Frontend:
- Add StageOffsetCalibrationTab (ui + logic) to FRAME Settings: runs an XY raster scan, polls heatmap, renders heatmap canvas, shows brightest spot and allows manual override + storing offsets via PositionerController.
- Add API clients: apiStageCenterCalibrationGetHeatmap, apiStageCenterCalibrationGetIsRunning, apiExperimentControllerRecaptureSlot.
- Wire a "Retake" button into OverviewRegistrationWizard to call ExperimentController.recaptureSlot and refresh overlay.
- Register the new Stage Offset Calibration tab in FRAMESettingsController.

Backend:
- Add ExperimentController.recaptureSlot API: computes slot center (from layout_data / labware / Heidstar fallback), moves stage to center, and reuses snapOverviewImage to replace a single slot snapshot.
- Rework StageCenterCalibrationController: replace legacy spiral worker with a deterministic raster scan that collects (x,y,mean_intensity) samples, exposes performCalibration/getCalibrationHeatmap/getIsCalibrationRunning/stopCalibration, returns structured results including brightest spot and metadata, emits progress, and saves CSVs. Minor MovementController cleanup.

Purpose: enable accurate stage offset calibration via a heatmap-driven raster scan and let users selectively retake individual overview slots without re-running the full registration.
Add a redesigned two-step Stage Offset Calibration flow and supporting APIs.

Frontend: - New backend API wrappers: getKnownCalibrationLayouts, getKnownCalibrationPoint, getOverviewAsyncStatus, getRecommendedScanParameters. - Major rewrite of StageOffsetCalibrationTab: introduces LayoutMapMini and HeatmapCanvas, adaptive recommended scan defaults, polling-driven run state, click-to-move stage, merge of backend-known layouts with fallbacks, removal of exposure input (managed by detector), improved UX for known vs measured points, and persisting offsets via setStageOffsetAxis using known+current positions. - Integrates position state and positioner move API calls.

Backend: - StageCenterCalibrationController: added getRecommendedScanParameters to compute pixel-size/FOV-based defaults; updated raster worker to use explicit keyword args for stage.move; minor cleanup. - VirtualCameraManager: change initial _running flag to False.

These changes provide adaptive scan defaults, a visual layout map and heatmap for easier calibration, and the API endpoints required by the new UI.
Prevent long-running overview endpoints from blocking FastAPI workers by running recapture and autonomous scan work in background threads and exposing a polling endpoint. Frontend: import and poll apiExperimentControllerGetOverviewAsyncStatus in OverviewRegistrationWizard and OverviewScanTab, wait for completion (with timeouts) before refreshing overlay/using results. Backend: add async bookkeeping (_overview_async_lock, thread, _overview_async_status), _tryStartOverviewAsync/_finishOverviewAsync helpers, getOverviewAsyncStatus API, convert recaptureSlot and runAutonomousOverviewScan to spawn daemon worker threads (with corresponding _...Blocking and worker methods), and surface errors/results via the shared status. Also add known calibration point APIs for use by the frontend.
Refactor frontend objective handling and backend status reporting.

- Removed legacy FRAMESettings/ObjectiveControllerTab and wired the settings tab to the ExtendedObjectiveController component.
- ObjectiveController UI: generalized movePositioner to accept an axis, added Z-axis controls and larger step buttons, consolidated repeated set-position handlers into a single helper with numeric validation and user confirmation, added confirmation when saving objective metadata.
- ObjectiveSwitcher: show objective names and magnifications in labels, improved spinner styling.
- Wizard steps (2-6): use apiObjectiveControllerSetObjectiveParameters to persist metadata, use fetchObjectiveControllerGetStatus where appropriate, reuse PositionSlice state, add periodic polling of positions, and shift objective slot indexing to match backend (0/1). Added confirmation dialogs before saving X/Z positions.
- WebSocketHandler: enhanced parsing of sigObjectiveChanged payload and robustly dispatches many objective-related fields (positions, available objective lists, magnifications, NAs, pixel sizes, current slot).
- fetchObjectiveControllerGetStatus: hardened null checks, dispatch additional fields and available objective arrays safely.
- Backend ObjectiveController: stop forcing currentObjective after homing, centralize per-slot pixel-size lookup (integrates PixelCalibrationController when available), and include per-slot pixel sizes and other availability lists in getstatus response for frontend compatibility.

These changes tighten frontend/backend synchronization for objective state, improve UX (confirmation/prompts, bigger moves, clearer labels), and make the status updates more robust.
Add per-detector stream parameter persistence and front-end/back-end syncing. Frontend: new API helper apiLiveViewControllerSetDetectorStreamParameters, LiveView now passes saved per-detector overrides when starting streams and stores effective params returned by the backend into Redux. StreamControlOverlay loads per-detector settings from backend, updates Redux when the user changes stream settings, and fire-and-forgets saves them to the backend. DetectorParameters polling useEffect was commented out to avoid unnecessary overhead. LiveStreamSlice: added perDetectorSettings state and reducers (setPerDetectorSettings, updateDetectorSettings). Backend (LiveViewController): added _detectorParams storage, use saved per-detector params when starting streams, persist effective params, include per_detector in settings responses, and new API method setDetectorStreamParameters to update (and optionally restart) active detector streams. These changes allow detector-specific tuning to survive detector switches and keep UI and controller state in sync.
beniroquai and others added 30 commits May 22, 2026 08:53
This pull request refactors the detector parameters UI to use Redux
state and real-time WebSocket updates, providing a more responsive and
robust experience. The component now updates immediately when the
backend changes detector parameters (such as in auto mode), and the UI
is improved with more intuitive controls and tooltips. A new Redux slice
manages detector parameters, and the WebSocket middleware is updated to
handle parameter updates from the backend.

**State management and real-time updates:**
- Migrated detector parameter state from local React state to Redux,
using a new `DetectorParametersSlice` to manage parameters and
synchronize with backend changes via WebSocket events.
(`frontend/src/components/DetectorParameters.js`,
`frontend/src/state/slices/DetectorParametersSlice.js`)
[[1]](diffhunk://#diff-25d76cc3b9cc2197b98a1b074830e1546d58a9e97c2bca8a6237a479c042e918R2-R58)
[[2]](diffhunk://#diff-d4c1e49f99af823758be1b5c723e470d8c1900b0b741aac2333e39603a4c0688R1-R88)
- Updated WebSocket middleware to handle `sigDetectorParametersUpdated`
events, normalizing and updating detector parameters in Redux when they
change on the backend. (`frontend/src/middleware/WebSocketHandler.js`)
[[1]](diffhunk://#diff-ec45c3c062d1c05c1ed80ec918a53dbb6159547f9a26f52e5d0807ac4cde9a67R23)
[[2]](diffhunk://#diff-ec45c3c062d1c05c1ed80ec918a53dbb6159547f9a26f52e5d0807ac4cde9a67R880-R905)

**UI/UX improvements:**
- Redesigned the detector parameters UI to use grid layouts, add
increment/decrement buttons for numeric fields, and provide tooltips and
info icons for better usability and clarity.
(`frontend/src/components/DetectorParameters.js`)
[[1]](diffhunk://#diff-25d76cc3b9cc2197b98a1b074830e1546d58a9e97c2bca8a6237a479c042e918L171-R204)
[[2]](diffhunk://#diff-25d76cc3b9cc2197b98a1b074830e1546d58a9e97c2bca8a6237a479c042e918R214-R402)
[[3]](diffhunk://#diff-25d76cc3b9cc2197b98a1b074830e1546d58a9e97c2bca8a6237a479c042e918L218-R452)
- Added an "Auto once" button for single-pass auto-exposure, with proper
disabling and loading feedback.
(`frontend/src/components/DetectorParameters.js`)

**Code quality and maintainability:**
- Refactored event handlers to immediately update Redux state and
backend on user input, and to sync local UI fields with Redux state only
when not being edited. (`frontend/src/components/DetectorParameters.js`)
[[1]](diffhunk://#diff-25d76cc3b9cc2197b98a1b074830e1546d58a9e97c2bca8a6237a479c042e918L70-R123)
[[2]](diffhunk://#diff-25d76cc3b9cc2197b98a1b074830e1546d58a9e97c2bca8a6237a479c042e918L114-R156)

These changes make detector parameter handling more robust, real-time,
and user-friendly.
This pull request introduces a new "Calibration" app category to the
frontend, reorganizing several hardware calibration-related tools into
this category and updating the sidebar navigation and color scheme to
support it. It also bumps the application version to 1.6.6.

**Key changes:**

**1. New Calibration Category and Navigation Updates**
- Added a new `CALIBRATION` category to `APP_CATEGORIES` and assigned a
unique color to it in `sidebarColors.js`.
[[1]](diffhunk://#diff-779574da60c9977138085f33039af263256f6d02882260f1b0b061fe7653d33aR41)
[[2]](diffhunk://#diff-9b49894ff755e129b54d0900b055748149d23f377fa717c6f31f520de006ec92R17)
- Updated the sidebar navigation (`NavigationDrawer.jsx`) to display a
collapsible "Calibration" group with its own icon and color, shown only
if calibration apps are enabled.
[[1]](diffhunk://#diff-a5adf019ae37a47eee448df08f4dcce7c8d7d0d74de2be463e1437d3fb1da1ccR3)
[[2]](diffhunk://#diff-a5adf019ae37a47eee448df08f4dcce7c8d7d0d74de2be463e1437d3fb1da1ccR74)
[[3]](diffhunk://#diff-a5adf019ae37a47eee448df08f4dcce7c8d7d0d74de2be463e1437d3fb1da1ccR251-R272)

**2. App Registry Reorganization**
- Moved several apps from the "System" and "Apps" categories into the
new "Calibration" category in `appRegistry.js`, including "FRAME
Settings", "Stage Center Calibration", "Objective Controller", and
"Stage Offset Calibration".
[[1]](diffhunk://#diff-779574da60c9977138085f33039af263256f6d02882260f1b0b061fe7653d33aL207-R208)
[[2]](diffhunk://#diff-779574da60c9977138085f33039af263256f6d02882260f1b0b061fe7653d33aL395-R396)
[[3]](diffhunk://#diff-779574da60c9977138085f33039af263256f6d02882260f1b0b061fe7653d33aL511-R528)
[[4]](diffhunk://#diff-779574da60c9977138085f33039af263256f6d02882260f1b0b061fe7653d33aL543-R550)
- Updated keywords for relevant apps to include "calibration" where
appropriate.
[[1]](diffhunk://#diff-779574da60c9977138085f33039af263256f6d02882260f1b0b061fe7653d33aL511-R528)
[[2]](diffhunk://#diff-779574da60c9977138085f33039af263256f6d02882260f1b0b061fe7653d33aL630-R643)

**3. UI and Icon Enhancements**
- Added the `TuneIcon` for the calibration category and updated all
relevant UI components to use this icon for calibration-related entries.
[[1]](diffhunk://#diff-f58b57cee8fc5a505161ff77b0b6f6e419886e78bb1c48097ff7761e84fda5bfR32)
[[2]](diffhunk://#diff-a5adf019ae37a47eee448df08f4dcce7c8d7d0d74de2be463e1437d3fb1da1ccR3)
- Updated `AppManager.jsx` to include the new "Calibration" category
with its icon, color, and description.

**4. Version Bump**
- Bumped the application version to 1.6.6 in `package.json`,
`package-lock.json`, and `version.js` to reflect these changes.
[[1]](diffhunk://#diff-da6498268e99511d9ba0df3c13e439d10556a812881c9d03955b2ef7c6c1c655L3-R3)
[[2]](diffhunk://#diff-4a2d9aa3e849b134993936ca81b83fb139edd2b0218077ab0f403b8c4803c62aL3-R9)
[[3]](diffhunk://#diff-d3ccf8195e0a16ec5e975768c8b2ef7132d7e5ffb2bd8806204d7b3c6030bb2eL5-R5)
Refactor goniometer contact-angle pipeline to auto-detect hydrophobic vs hydrophilic regimes and measure accordingly. Adds scipy.uniform_filter1d; replaces monolithic fit logic with detect_regime, measure_hydrophilic and measure_hydrophobic helpers; supports both y(x) and x(y) fit modes and a waist-rise threshold for hydrophobic detection. Simplifies/defaults config (fit_frac, poly_degree, angle_range, waist_rise_thresh) and returns an is_hydrophobic flag in results. draw_result updated to render both modes and improved annotations; resizing/thumbnail behavior adjusted. The previous implementation is preserved as GoniometerController_old.py for reference.
This pull request introduces several improvements and cleanups across
the codebase, most notably adding comprehensive documentation for
Opentrons-style labware integration in ImSwitch, enhancing the
frontend's Axon tab with a new Overview Scan feature, and refining the
overview registration workflow. Additionally, it removes obsolete or
development-only files and makes small adjustments for better
cross-platform support.

**Documentation and Labware Integration:**
- Added a detailed `docs/labware_opentrons.md` guide describing how
Opentrons-compatible labware is integrated, discovered, and used within
ImSwitch, including backend structure, HTTP endpoints, frontend
integration, and OME-NGFF metadata output.

**Frontend Features and Improvements:**
- Added the `OverviewScanTab` component to the Axon tab's UI, updating
`AxonTabComponent.js` to include the new tab and its contents.
[[1]](diffhunk://#diff-4c8a9e79a2b661c2650e1175329608109c10555790a3f830b13b35e071778e3bR16)
[[2]](diffhunk://#diff-4c8a9e79a2b661c2650e1175329608109c10555790a3f830b13b35e071778e3bL70-R72)
[[3]](diffhunk://#diff-4c8a9e79a2b661c2650e1175329608109c10555790a3f830b13b35e071778e3bR81)
- Improved the overview registration wizard
(`OverviewRegistrationWizard.js`) so the MJPEG stream URL is built
whenever the wizard is open, regardless of camera availability, and
enhanced metadata persistence by storing the stage position at snapshot
time for later autonomous scanning.
[[1]](diffhunk://#diff-523fc4c0ff129da7efc91bbf23940cc50dd9d4b3148e34182db5cdae58c6fa30L92-R97)
[[2]](diffhunk://#diff-523fc4c0ff129da7efc91bbf23940cc50dd9d4b3148e34182db5cdae58c6fa30L103)
[[3]](diffhunk://#diff-523fc4c0ff129da7efc91bbf23940cc50dd9d4b3148e34182db5cdae58c6fa30R354-R356)

**Configuration and Dependency Cleanups:**
- Removed the `.readthedocs.yaml` file, indicating a possible shift away
from Read the Docs for documentation builds.
- Added a Windows-specific Python launch configuration to
`.vscode/launch.json` for improved cross-platform development support.
- Updated `package-lock.json` to add a new `yaml` dependency under the
`tailwindcss` node_modules tree, likely as a transitive dependency.

**Maintenance and Cleanup:**
- Removed the `frontend/scripts/create_test_animations.sh` script, which
was used for generating placeholder GIFs for acceptance testing,
indicating these assets or their creation are no longer needed.
- Deleted the development/test server implementation in
`frontend/python/server.py`, further cleaning up unused or obsolete
files.
This PR automatically sets the backend and frontend's version strings
from VCS information available during the build CI workflows, in order
to remove the need to manually/automatically create VCS commits for
updating version strings after changes are made.

The version strings produced by this PR do not follow the pseudoversion
format used in Go Modules or Forklift; instead, they look something like
"v2.1.192-89-g930ffbe-t20260523153301-pr278" for PR commits and
something like "v2.1.192-89-g930ffbe-t20260523153301" for non-PR
commits. For builds of pushed tags, they should look like "v2.2.0" (but
that functionality is not yet tested).

This work is tracked on Notion at
https://www.notion.so/Bake-VCS-info-into-the-ImSwitch-container-image-3574e612c78a8053929ce57897eee6c7?source=copy_link
…lly handled by the first pass). Add a _sdk_convert_works flag that

is True only on macOS(?), on the first failure it is set to False so subsequent frames go straight to OpenCV without the wasted SDK call
This pull request refactors the detector parameters UI to use Redux
state and real-time WebSocket updates, providing a more responsive and
robust experience. The component now updates immediately when the
backend changes detector parameters (such as in auto mode), and the UI
is improved with more intuitive controls and tooltips. A new Redux slice
manages detector parameters, and the WebSocket middleware is updated to
handle parameter updates from the backend.

**State management and real-time updates:**
- Migrated detector parameter state from local React state to Redux,
using a new `DetectorParametersSlice` to manage parameters and
synchronize with backend changes via WebSocket events.
(`frontend/src/components/DetectorParameters.js`,
`frontend/src/state/slices/DetectorParametersSlice.js`)
[[1]](diffhunk://#diff-25d76cc3b9cc2197b98a1b074830e1546d58a9e97c2bca8a6237a479c042e918R2-R58)
[[2]](diffhunk://#diff-d4c1e49f99af823758be1b5c723e470d8c1900b0b741aac2333e39603a4c0688R1-R88)
- Updated WebSocket middleware to handle `sigDetectorParametersUpdated`
events, normalizing and updating detector parameters in Redux when they
change on the backend. (`frontend/src/middleware/WebSocketHandler.js`)
[[1]](diffhunk://#diff-ec45c3c062d1c05c1ed80ec918a53dbb6159547f9a26f52e5d0807ac4cde9a67R23)
[[2]](diffhunk://#diff-ec45c3c062d1c05c1ed80ec918a53dbb6159547f9a26f52e5d0807ac4cde9a67R880-R905)

**UI/UX improvements:**
- Redesigned the detector parameters UI to use grid layouts, add
increment/decrement buttons for numeric fields, and provide tooltips and
info icons for better usability and clarity.
(`frontend/src/components/DetectorParameters.js`)
[[1]](diffhunk://#diff-25d76cc3b9cc2197b98a1b074830e1546d58a9e97c2bca8a6237a479c042e918L171-R204)
[[2]](diffhunk://#diff-25d76cc3b9cc2197b98a1b074830e1546d58a9e97c2bca8a6237a479c042e918R214-R402)
[[3]](diffhunk://#diff-25d76cc3b9cc2197b98a1b074830e1546d58a9e97c2bca8a6237a479c042e918L218-R452)
- Added an "Auto once" button for single-pass auto-exposure, with proper
disabling and loading feedback.
(`frontend/src/components/DetectorParameters.js`)

**Code quality and maintainability:**
- Refactored event handlers to immediately update Redux state and
backend on user input, and to sync local UI fields with Redux state only
when not being edited. (`frontend/src/components/DetectorParameters.js`)
[[1]](diffhunk://#diff-25d76cc3b9cc2197b98a1b074830e1546d58a9e97c2bca8a6237a479c042e918L70-R123)
[[2]](diffhunk://#diff-25d76cc3b9cc2197b98a1b074830e1546d58a9e97c2bca8a6237a479c042e918L114-R156)

These changes make detector parameter handling more robust, real-time,
and user-friendly.
This pull request introduces a new "Calibration" app category to the
frontend, reorganizing several hardware calibration-related tools into
this category and updating the sidebar navigation and color scheme to
support it. It also bumps the application version to 1.6.6.

**Key changes:**

**1. New Calibration Category and Navigation Updates**
- Added a new `CALIBRATION` category to `APP_CATEGORIES` and assigned a
unique color to it in `sidebarColors.js`.
[[1]](diffhunk://#diff-779574da60c9977138085f33039af263256f6d02882260f1b0b061fe7653d33aR41)
[[2]](diffhunk://#diff-9b49894ff755e129b54d0900b055748149d23f377fa717c6f31f520de006ec92R17)
- Updated the sidebar navigation (`NavigationDrawer.jsx`) to display a
collapsible "Calibration" group with its own icon and color, shown only
if calibration apps are enabled.
[[1]](diffhunk://#diff-a5adf019ae37a47eee448df08f4dcce7c8d7d0d74de2be463e1437d3fb1da1ccR3)
[[2]](diffhunk://#diff-a5adf019ae37a47eee448df08f4dcce7c8d7d0d74de2be463e1437d3fb1da1ccR74)
[[3]](diffhunk://#diff-a5adf019ae37a47eee448df08f4dcce7c8d7d0d74de2be463e1437d3fb1da1ccR251-R272)

**2. App Registry Reorganization**
- Moved several apps from the "System" and "Apps" categories into the
new "Calibration" category in `appRegistry.js`, including "FRAME
Settings", "Stage Center Calibration", "Objective Controller", and
"Stage Offset Calibration".
[[1]](diffhunk://#diff-779574da60c9977138085f33039af263256f6d02882260f1b0b061fe7653d33aL207-R208)
[[2]](diffhunk://#diff-779574da60c9977138085f33039af263256f6d02882260f1b0b061fe7653d33aL395-R396)
[[3]](diffhunk://#diff-779574da60c9977138085f33039af263256f6d02882260f1b0b061fe7653d33aL511-R528)
[[4]](diffhunk://#diff-779574da60c9977138085f33039af263256f6d02882260f1b0b061fe7653d33aL543-R550)
- Updated keywords for relevant apps to include "calibration" where
appropriate.
[[1]](diffhunk://#diff-779574da60c9977138085f33039af263256f6d02882260f1b0b061fe7653d33aL511-R528)
[[2]](diffhunk://#diff-779574da60c9977138085f33039af263256f6d02882260f1b0b061fe7653d33aL630-R643)

**3. UI and Icon Enhancements**
- Added the `TuneIcon` for the calibration category and updated all
relevant UI components to use this icon for calibration-related entries.
[[1]](diffhunk://#diff-f58b57cee8fc5a505161ff77b0b6f6e419886e78bb1c48097ff7761e84fda5bfR32)
[[2]](diffhunk://#diff-a5adf019ae37a47eee448df08f4dcce7c8d7d0d74de2be463e1437d3fb1da1ccR3)
- Updated `AppManager.jsx` to include the new "Calibration" category
with its icon, color, and description.

**4. Version Bump**
- Bumped the application version to 1.6.6 in `package.json`,
`package-lock.json`, and `version.js` to reflect these changes.
[[1]](diffhunk://#diff-da6498268e99511d9ba0df3c13e439d10556a812881c9d03955b2ef7c6c1c655L3-R3)
[[2]](diffhunk://#diff-4a2d9aa3e849b134993936ca81b83fb139edd2b0218077ab0f403b8c4803c62aL3-R9)
[[3]](diffhunk://#diff-d3ccf8195e0a16ec5e975768c8b2ef7132d7e5ffb2bd8806204d7b3c6030bb2eL5-R5)
This PR automatically sets the backend and frontend's version strings
from VCS information available during the build CI workflows, in order
to remove the need to manually/automatically create VCS commits for
updating version strings after changes are made.

The version strings produced by this PR do not follow the pseudoversion
format used in Go Modules or Forklift; instead, they look something like
"v2.1.192-89-g930ffbe-t20260523153301-pr278" for PR commits and
something like "v2.1.192-89-g930ffbe-t20260523153301" for non-PR
commits. For builds of pushed tags, they should look like "v2.2.0" (but
that functionality is not yet tested).

This work is tracked on Notion at
https://www.notion.so/Bake-VCS-info-into-the-ImSwitch-container-image-3574e612c78a8053929ce57897eee6c7?source=copy_link
This pull request improves robustness and user feedback for stream and
detector parameter controls in the frontend, with a focus on error
handling, input validation, and UI consistency. The main changes include
better notification handling for backend errors, stricter validation for
detector black level input, and several UI/UX refinements.

**Input validation and API correctness:**

* Improved validation for the `blacklevel` detector parameter: negative
values are now prevented, and empty input is handled gracefully. Also
corrected the API parameter name from `blacklevel` to `blackLevel` for
backend compatibility.
[[1]](diffhunk://#diff-25d76cc3b9cc2197b98a1b074830e1546d58a9e97c2bca8a6237a479c042e918L138-R137)
[[2]](diffhunk://#diff-25d76cc3b9cc2197b98a1b074830e1546d58a9e97c2bca8a6237a479c042e918L211-R226)
[[3]](diffhunk://#diff-25d76cc3b9cc2197b98a1b074830e1546d58a9e97c2bca8a6237a479c042e918L476-R493)

**UI/UX refinements:**

* Adjusted overflow handling and scrolling behavior for the stream
control overlay for better layout consistency and usability.
[[1]](diffhunk://#diff-064fb804a25591ddf485bad6b26f788038dbe818cd2580bcd028a228e5790cc4L440-R461)
[[2]](diffhunk://#diff-064fb804a25591ddf485bad6b26f788038dbe818cd2580bcd028a228e5790cc4R583)
* Improved formatting and clarity of crop size controls and tab labels,
including better handling of max values and label wrapping.
[[1]](diffhunk://#diff-064fb804a25591ddf485bad6b26f788038dbe818cd2580bcd028a228e5790cc4L551-R573)
[[2]](diffhunk://#diff-064fb804a25591ddf485bad6b26f788038dbe818cd2580bcd028a228e5790cc4L681-R699)
[[3]](diffhunk://#diff-064fb804a25591ddf485bad6b26f788038dbe818cd2580bcd028a228e5790cc4L691-R726)
[[4]](diffhunk://#diff-064fb804a25591ddf485bad6b26f788038dbe818cd2580bcd028a228e5790cc4L709-R737)
* Cleaned up imports by removing unused components and icons for
maintainability.
[[1]](diffhunk://#diff-25d76cc3b9cc2197b98a1b074830e1546d58a9e97c2bca8a6237a479c042e918L14)
[[2]](diffhunk://#diff-064fb804a25591ddf485bad6b26f788038dbe818cd2580bcd028a228e5790cc4L1-R1)
[[3]](diffhunk://#diff-064fb804a25591ddf485bad6b26f788038dbe818cd2580bcd028a228e5790cc4L18-L31)

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This pull request introduces dynamic controller capability detection to
the frontend, ensuring that UI components and available applications
adapt based on the controllers currently available from the backend.
This prevents users from accessing features or apps that require
unavailable hardware, improving user experience and robustness. The main
changes include new hooks for controller detection, filtering of app
lists and navigation items, and conditional rendering of UI components
based on controller presence.

**Backend controller capability detection and state management:**

* Added a new hook `useBackendControllerCapabilities` that queries
available controllers from the backend and updates the Redux store; it
also ensures that the selected plugin is valid for the available
controllers, reverting to a safe default if necessary.
(`frontend/src/hooks/useBackendControllerCapabilities.js`,
`frontend/src/App.jsx`)
[[1]](diffhunk://#diff-1e38214eb3b82d0e040a32ce6e048e1c18528a003ec8b0a4807b24f0d7888ef3R1-R48)
[[2]](diffhunk://#diff-a0eba768ed9d2a17091f82d46efb5e1c988f08185cc1e9989366995cdb4e3ba9R69)
[[3]](diffhunk://#diff-a0eba768ed9d2a17091f82d46efb5e1c988f08185cc1e9989366995cdb4e3ba9R200-R206)
* Implemented an API utility `apiGetAvailableControllers` to fetch the
list of available controllers from the backend.
(`frontend/src/backendapi/apiGetAvailableControllers.js`)

**App registry and filtering logic:**

* Extended the `APP_REGISTRY` to include a `requiredControllers` field
for each app, and added utility functions `isAppAvailableForControllers`
and `filterAppsByAvailableControllers` to filter apps based on available
controllers. (`frontend/src/constants/appRegistry.js`)
[[1]](diffhunk://#diff-779574da60c9977138085f33039af263256f6d02882260f1b0b061fe7653d33aR475)
[[2]](diffhunk://#diff-779574da60c9977138085f33039af263256f6d02882260f1b0b061fe7653d33aR531)
[[3]](diffhunk://#diff-779574da60c9977138085f33039af263256f6d02882260f1b0b061fe7653d33aR707)
[[4]](diffhunk://#diff-779574da60c9977138085f33039af263256f6d02882260f1b0b061fe7653d33aR727-R748)

**UI adaptation based on controller capabilities:**

* Updated `AppManager` and `NavigationDrawer` to only display and enable
apps that are compatible with the currently available controllers.
(`frontend/src/components/AppManager/AppManager.jsx`,
`frontend/src/components/navigation/NavigationDrawer.jsx`)
[[1]](diffhunk://#diff-f58b57cee8fc5a505161ff77b0b6f6e419886e78bb1c48097ff7761e84fda5bfL47-R62)
[[2]](diffhunk://#diff-f58b57cee8fc5a505161ff77b0b6f6e419886e78bb1c48097ff7761e84fda5bfL281-R311)
[[3]](diffhunk://#diff-f58b57cee8fc5a505161ff77b0b6f6e419886e78bb1c48097ff7761e84fda5bfL298-R320)
[[4]](diffhunk://#diff-f58b57cee8fc5a505161ff77b0b6f6e419886e78bb1c48097ff7761e84fda5bfL343-R368)
[[5]](diffhunk://#diff-f58b57cee8fc5a505161ff77b0b6f6e419886e78bb1c48097ff7761e84fda5bfL353-R378)
[[6]](diffhunk://#diff-f58b57cee8fc5a505161ff77b0b6f6e419886e78bb1c48097ff7761e84fda5bfL371-R396)
[[7]](diffhunk://#diff-f58b57cee8fc5a505161ff77b0b6f6e419886e78bb1c48097ff7761e84fda5bfL470-R498)
[[8]](diffhunk://#diff-a5adf019ae37a47eee448df08f4dcce7c8d7d0d74de2be463e1437d3fb1da1ccL17-R22)
[[9]](diffhunk://#diff-a5adf019ae37a47eee448df08f4dcce7c8d7d0d74de2be463e1437d3fb1da1ccR51-R62)

* Modified `FRAMESettingsController` and `LiveView` to conditionally
render tabs and controls (e.g., Objective, Extended LED Matrix) only if
the corresponding controllers are available, and to automatically switch
tabs if a required controller becomes unavailable.
(`frontend/src/components/FRAMESettingsController.js`,
`frontend/src/components/LiveView.js`)
[[1]](diffhunk://#diff-194d2e57e59f11829fe532a192e21b99a8fcfa0f157a5bb6760fd283ec9e5495L1-R10)
[[2]](diffhunk://#diff-194d2e57e59f11829fe532a192e21b99a8fcfa0f157a5bb6760fd283ec9e5495L22-L57)
[[3]](diffhunk://#diff-98c10fd4b655ab7b1f6ad50e69ded7733ec826bf99fa81a60ddd9e2eaa613d07R30)
[[4]](diffhunk://#diff-98c10fd4b655ab7b1f6ad50e69ded7733ec826bf99fa81a60ddd9e2eaa613d07R67-R72)
[[5]](diffhunk://#diff-98c10fd4b655ab7b1f6ad50e69ded7733ec826bf99fa81a60ddd9e2eaa613d07R676-R677)
[[6]](diffhunk://#diff-98c10fd4b655ab7b1f6ad50e69ded7733ec826bf99fa81a60ddd9e2eaa613d07R692-R693)
[[7]](diffhunk://#diff-98c10fd4b655ab7b1f6ad50e69ded7733ec826bf99fa81a60ddd9e2eaa613d07R739-R751)

These changes ensure that the frontend always reflects the actual
hardware/software capabilities reported by the backend, preventing UI
errors and improving user guidance.

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This pull request makes several improvements to the frontend UI
components for stage, illumination, and objective control, focusing on
code readability, UI clarity, and enhanced user interaction. The main
changes include UI enhancements for better grouping and labeling,
improved code formatting for consistency, and the addition of new
features such as Z-leveling toggle for objectives and iconography for
different sections.

**UI Enhancements and User Experience:**

* Replaced detector selection `Tabs` with a `ButtonGroup` in
`LiveView.js` for clearer detector selection and improved accessibility.
Added section icons (e.g., for Stage Control, Autofocus, Illumination,
Objective, Detector Trigger) and tooltips for better user guidance.
[[1]](diffhunk://#diff-98c10fd4b655ab7b1f6ad50e69ded7733ec826bf99fa81a60ddd9e2eaa613d07R8-R23)
[[2]](diffhunk://#diff-98c10fd4b655ab7b1f6ad50e69ded7733ec826bf99fa81a60ddd9e2eaa613d07L543-R600)
[[3]](diffhunk://#diff-98c10fd4b655ab7b1f6ad50e69ded7733ec826bf99fa81a60ddd9e2eaa613d07R747-R762)
[[4]](diffhunk://#diff-98c10fd4b655ab7b1f6ad50e69ded7733ec826bf99fa81a60ddd9e2eaa613d07R782-R810)
[[5]](diffhunk://#diff-98c10fd4b655ab7b1f6ad50e69ded7733ec826bf99fa81a60ddd9e2eaa613d07R823-R826)
* Changed the "Home All" button color in `AxisControl.jsx` from
secondary to primary for better visual prominence.
* Improved section labeling and grouping (e.g., "Axis View", "Joystick",
"Virtual Joystick") for more intuitive navigation in the right panel.

**Illumination Controller Code Quality and Consistency:**

* Refactored all fetch API calls in `IlluminationController.js` for
improved readability and consistent multi-line formatting. Enhanced
error handling and Redux state initialization for laser sources.
[[1]](diffhunk://#diff-606733c39a7cbf75c555963223773a56c0b0e003296d940dca90b6bfb0667047L15-R20)
[[2]](diffhunk://#diff-606733c39a7cbf75c555963223773a56c0b0e003296d940dca90b6bfb0667047L36-R40)
[[3]](diffhunk://#diff-606733c39a7cbf75c555963223773a56c0b0e003296d940dca90b6bfb0667047L48-R52)
[[4]](diffhunk://#diff-606733c39a7cbf75c555963223773a56c0b0e003296d940dca90b6bfb0667047L61-R67)
[[5]](diffhunk://#diff-606733c39a7cbf75c555963223773a56c0b0e003296d940dca90b6bfb0667047L71-R112)
[[6]](diffhunk://#diff-606733c39a7cbf75c555963223773a56c0b0e003296d940dca90b6bfb0667047L102-R127)
[[7]](diffhunk://#diff-606733c39a7cbf75c555963223773a56c0b0e003296d940dca90b6bfb0667047L121-R161)
[[8]](diffhunk://#diff-606733c39a7cbf75c555963223773a56c0b0e003296d940dca90b6bfb0667047L142-R177)
* Improved UI code formatting for the laser slider and value display,
and removed the redundant instructional `Typography` since tooltip help
is now provided.
[[1]](diffhunk://#diff-606733c39a7cbf75c555963223773a56c0b0e003296d940dca90b6bfb0667047L157-L163)
[[2]](diffhunk://#diff-606733c39a7cbf75c555963223773a56c0b0e003296d940dca90b6bfb0667047L180-R238)

**Objective Controller Improvements:**

* Added a Z-leveling toggle (`Switch`) to `ObjectiveSwitcher.js`,
allowing users to enable or disable Z-leveling when switching
objectives. Refactored the objective switching logic to respect this
toggle.
[[1]](diffhunk://#diff-8dbccd645a421cdf580b426f89f4259ce8d8921ce3068d257ad6969ae7320f4cR5-R9)
[[2]](diffhunk://#diff-8dbccd645a421cdf580b426f89f4259ce8d8921ce3068d257ad6969ae7320f4cL15-R24)
[[3]](diffhunk://#diff-8dbccd645a421cdf580b426f89f4259ce8d8921ce3068d257ad6969ae7320f4cL45-R56)

**Minor Consistency and Readability Updates:**

* Updated arrow function formatting and argument parentheses for
consistency throughout the codebase.
[[1]](diffhunk://#diff-606733c39a7cbf75c555963223773a56c0b0e003296d940dca90b6bfb0667047L36-R40)
[[2]](diffhunk://#diff-606733c39a7cbf75c555963223773a56c0b0e003296d940dca90b6bfb0667047L48-R52)
* Added missing trailing commas in multi-line function calls for
improved diff clarity and code style.
[[1]](diffhunk://#diff-8ae8ac1715ced9cb4171f62ce0f7e923dc31fef5545b83813f4079190866a024L64-R64)
[[2]](diffhunk://#diff-8ae8ac1715ced9cb4171f62ce0f7e923dc31fef5545b83813f4079190866a024L101-R113)
[[3]](diffhunk://#diff-606733c39a7cbf75c555963223773a56c0b0e003296d940dca90b6bfb0667047L61-R67)
[[4]](diffhunk://#diff-606733c39a7cbf75c555963223773a56c0b0e003296d940dca90b6bfb0667047L71-R112)

These changes collectively enhance the maintainability and usability of
the frontend, making the UI more intuitive and the code easier to read
and extend.
This pull request removes the old standalone calibration plugin UIs and
centralizes stage offset calibration directly in the
`WellSelectorCanvas` context menu, making the workflow safer and more
consistent. It also introduces Ashlar stitching as a selectable mode in
the experiment designer, with automatic triggering when experiments
finish, and adds new backend API bindings to support these workflows.

**Calibration workflow improvements:**

* Removed the `StageOffsetCalibration` and
`StageCenterCalibrationWizard` plugin components and their corresponding
UI entries in `App.jsx`, consolidating all calibration into the
`WellSelectorCanvas` right-click context menu.
[[1]](diffhunk://#diff-a0eba768ed9d2a17091f82d46efb5e1c988f08185cc1e9989366995cdb4e3ba9L28-R28)
[[2]](diffhunk://#diff-a0eba768ed9d2a17091f82d46efb5e1c988f08185cc1e9989366995cdb4e3ba9L44)
[[3]](diffhunk://#diff-a0eba768ed9d2a17091f82d46efb5e1c988f08185cc1e9989366995cdb4e3ba9L536-L538)
[[4]](diffhunk://#diff-a0eba768ed9d2a17091f82d46efb5e1c988f08185cc1e9989366995cdb4e3ba9L627-L629)
* Added a confirmation dialog for "We are here (calibrate offset)" in
`WellSelectorCanvas`, ensuring users confirm before overwriting the
stage offset. The dialog snapshots the raw device position before
writing, making the calibration atomic and robust.
[[1]](diffhunk://#diff-f9970f763f41caebe7bc5a295307ad98326a6de46dd85b11c15ae77b97fdb37fR68-R74)
[[2]](diffhunk://#diff-f9970f763f41caebe7bc5a295307ad98326a6de46dd85b11c15ae77b97fdb37fL1627-L1655)
[[3]](diffhunk://#diff-f9970f763f41caebe7bc5a295307ad98326a6de46dd85b11c15ae77b97fdb37fR1723-R1788)
* Updated the offset calibration API contract and logic to use explicit
device positions for deterministic calibration, and added a new API
binding to fetch the raw device position
(`apiPositionerControllerGetDevicePositionAxis`).
[[1]](diffhunk://#diff-9f0061e8db6d5946e7e4a00f4b00f05761dafd2cd0297480f0c2a4d7ecf3467eL2-R39)
[[2]](diffhunk://#diff-1651e146e302b8aec2ee0e93bb454aa1f9979e027e53ec7b37b0bfe4e31ca87eR1-R24)

**Experiment stitching enhancements:**

* Added Ashlar stitching as a new selectable mode in the tiling UI, with
state wiring to enable/disable it. When enabled, Ashlar stitching is
triggered automatically when an experiment finishes, with user feedback
in the UI.
[[1]](diffhunk://#diff-398755f7efc456e680e858235568936d178193e314b370b2d52d0180d9605a53L222-R231)
[[2]](diffhunk://#diff-398755f7efc456e680e858235568936d178193e314b370b2d52d0180d9605a53R251-R258)
[[3]](diffhunk://#diff-b04ccf6b6d7a6afaf25775f6c193446d8c5b87715fff7b650a1b22bca45dc988R55)
[[4]](diffhunk://#diff-b04ccf6b6d7a6afaf25775f6c193446d8c5b87715fff7b650a1b22bca45dc988R104-R132)
[[5]](diffhunk://#diff-92dde5a733fda5309ba396ffa8e5dedfe72530b4f5b8854fc100d78f29e14221R1-R28)

**API and code cleanup:**

* Removed the unused `apiStageCenterCalibrationGetStatus.js` and added a
new API binding for fetching the latest heatmap for center calibration
(`apiStageCenterCalibrationGetLatestHeatmap`).
[[1]](diffhunk://#diff-497310f2faca9db18e2055868da8f1ccc1f8e1b3ed6389579383a377bcd2ec4dL1-L29)
[[2]](diffhunk://#diff-f18f085a2774b63f41b19d9a2af0ef13212105b4c90f5b91183c395df64b1a2eR1-R23)

These changes streamline calibration workflows, reduce user error, and
add robust experiment stitching options.

---------

Co-authored-by: Copilot <copilot@github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants