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 IS — OverlayPanel 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:
- Snapshot the active non-planar move spans in the host.
- Regenerate a baseline with
enableNonPlanar=0. - Snapshot the baseline before any later generation invalidates the engine buffer.
- Restore/present the active path and draw the baseline in a second painter pass.
- 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 TOOLPATHwarning 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¶
- Non-Planar controls for the three planned overlay ids and ghost verification.
- Honesty for generated-versus-parsed provenance and export warnings.
- Slicer — interaction map for today’s preview controls.
- Simulator — interaction map for today’s scrubber and overlays.