Skip to content

Preview stage

Status: PROPOSED

Preview is the planned stage in docs/ui/ui-plan.md:95–118,197–206. Everything below is PROPOSED unless explicitly tagged HOW IT IS with a code citation.

Preview answers four questions: which layers are visible, what each color means, where the current move sits, and whether the result is safe to export.

flowchart LR
  G["Generated or parsed toolpath"] --> L["Choose layer band"]
  L --> C["Choose color-by field"]
  C --> S["Scrub moves and inspect HUD"]
  S --> F["Open findings or compare ghost"]
  F --> E["Export generated path"]

Layer band

PROPOSED — the current single vertical slider becomes a dual-range slider:

Part Behavior Hook
Lower thumb Hide layers below the selected minimum Host-side painter filter; no new layer-mask export
Upper thumb Hide layers above the selected maximum Existing ViewportSetLayerVisibility followed by ViewportBuildBuffers
Band Drag the visible min–max window together Host-side dual-range state
Label Show Layers 12–48 / 120 Real layer count from ViewportGetLayerCount

HOW IT IS — both apps currently mount a single LayerSlider (src/SlicerApp/MainWindow.axaml:26–28; src/SimulatorApp/MainWindow.axaml:24–26). The Slicer routes changes through SetLayerVisibility and buffer rebuild (src/SlicerApp/MainWindow.axaml.cs:741–751; src/Nps.Shell/ViewportController.cs:252–257,657–661). Parsed paths already grow the single slider from their real move layers (src/SlicerApp/MainWindow.axaml.cs:477–500). The ABI’s direct ViewportGetLayerCount query exists but has no production UI consumer (src/Nps.EngineHost/NpsAbi.cs:408–409).

Color by

PROPOSED — one toolbar dropdown becomes the single home for color mapping; the Overlays inspector mirrors the same selection. The contract names eight UI ids:

Id User label Honesty
motion-type Motion type / no analysis heatmap HOW IT IS selector id (src/Nps.EngineHost/NpsAbi.cs:88–90; src/Nps.Shell/Controls/OverlayPanel.axaml:9)
thermal Thermal / heat HOW IT IS selector id (src/Nps.EngineHost/NpsAbi.cs:91; src/Nps.Shell/Controls/OverlayPanel.axaml:10)
warp-risk Warp risk HOW IT IS selector id (src/Nps.EngineHost/NpsAbi.cs:92; src/Nps.Shell/Controls/OverlayPanel.axaml:11)
bond-strength Stress / bond HOW IT IS selector id (src/Nps.EngineHost/NpsAbi.cs:93; src/Nps.Shell/Controls/OverlayPanel.axaml:12)
cooling-eff Cooling HOW IT IS selector id (src/Nps.EngineHost/NpsAbi.cs:94; src/Nps.Shell/Controls/OverlayPanel.axaml:13)
nonplanar-amplitude Non-planar amplitude PROPOSED additive overlay id
collision-risk Collision risk PROPOSED additive overlay id
region-mask Region mask PROPOSED additive overlay id

HOW IT IS — selecting one of the five current radios calls the one-shot ViewportApplyOverlay path and updates legend range/stats (src/Nps.Shell/ViewportController.cs:517–547,564–639). The dropdown and three non-planar ids are PROPOSED. The dropdown is populated through the existing, currently unconsumed GetSupportedOverlayIds export (src/Nps.EngineHost/NpsAbi.cs:467–474).

Display toggles

Toggle Planned effect Status
Travels Show/hide travel moves HOW IT IS — toolbar toggle exists and defaults on (src/Nps.Shell/Controls/ViewportToolbar.cs:60–61,77)
Extrusions Show/hide extrusion moves HOW IT IS — toolbar toggle exists and defaults on (src/Nps.Shell/Controls/ViewportToolbar.cs:63–64,78)
Seams Show/hide seam markers PROPOSED
Retractions Show/hide retraction markers/moves PROPOSED
Ghost lower Show/hide the dim comparison baseline PROPOSED
Single layer Restrict rendering to one selected layer PROPOSED host-side filter

These are display filters. They do not regenerate or change exported G-code.

Interactive legend

PROPOSED — the legend extends the current range display:

  • Click a legend class to show or hide it.
  • Hover a class to see its move/time fraction.
  • Keep units, low/high values, and inversion visible.
  • Use viewport-content color ramps, not new chrome colors.

HOW IT ISOverlayPanel already displays low/high labels, a gradient, and stats text (src/Nps.Shell/Controls/OverlayPanel.axaml:15–35). Clicking and hovering legend entries are PROPOSED.

Statistics HUD and status estimates

PROPOSED — a left-sidebar section in Preview shows:

Value Empty value
Estimated time --
Filament length and mass --
Layer and move counts -- until a toolpath is present
Non-planar move count --

The same time and filament summary appears in the status bar. Both depend on a new additive GetLastGcodeStats(NpsGcodeStats) export. Until that export exists, the UI shows --; it must not invent estimates.

Time / move scrub

PROPOSED — a horizontal scrubber at the viewport bottom moves the playhead without creating a third simulation model. It uses the same ViewportSetSimulationState path as playback.

HOW IT IS — the Simulator scrubber already commits a move index through SetSimulationState and rebuilds buffers (src/SimulatorApp/MainWindow.axaml.cs:850–866). Pressing it pauses playback and release resumes only if playback was previously running (src/SimulatorApp/MainWindow.axaml.cs:868–915). Preview promotes that engine path to a stage-level scrub surface; Slicer has no scrubber today.

Ghost compare

PROPOSED — Ghost Compare shows a dim planar baseline under the active non-planar path:

  1. Snapshot the active non-planar move spans in the host.
  2. Regenerate a baseline with enableNonPlanar=0.
  3. Snapshot the baseline before any later generation invalidates the engine buffer.
  4. Restore/present the active path and draw the baseline in a second painter pass.
  5. Scrub curved layers to inspect stair-step reduction.

Warning

The engine-owned move pointer is invalidated by later load, generate, or parse operations (src/Nps.EngineHost/EngineSession.cs:392–400). Ghost Compare therefore snapshots data before baseline regeneration; it must not hold two live engine spans.

Dirty banner

PROPOSED — after a generated path exists, the host stores a snapshot hash of slice and non-planar settings. A later edit produces a full-width banner:

Settings changed since last slice — Re-slice · Dismiss

The titlebar CTA changes from Slice to Re-slice. Dismiss hides the banner but does not mark the result current. Loading parsed G-code does not create a fake “slice settings” relationship.

Post-slice offer

PROPOSED — successful generation creates a non-blocking toast:

Slice complete — View Preview

The toast auto-dismisses and never forces a stage change. Failed or zero-move generation produces an error/status state, not a success offer.

Export

PROPOSED — Export is enabled only for a path generated in the current session. Parsed external G-code remains inspectable but Export is disabled with the reason “Nothing generated in this session.”

The export dialog:

  • shows target filename and a size/preflight result;
  • repeats the DEMO TOOLPATH warning when the visible generated path is demo;
  • writes through existing WriteGcodeToFile;
  • records success or failure in Activity;
  • never relabels a demo path as a production slice.

WriteGcodeToFile and GenerateGcodeToBuffer already exist as ABI exports (src/Nps.EngineHost/NpsAbi.cs:347–359) but have no production UI consumer. The planned export dialog consumes them for preflight and final write. See Honesty for the provenance state machine.

Toolbar additions

HOW IT IS — the current toolbar has ten controls: five camera presets, Zoom to Fit, travels/extrusions toggles, and layer up/down (src/Nps.Shell/Controls/ViewportToolbar.cs:29–38,53–67).

PROPOSED — Preview adds Color by, Ghost, Paint, and a clip-plane slider. Clip requires an additive ViewportSetClipPlane export; it is not presented as working before that export lands.

See also