FOrcaSlicer — Flexible OrcaSlicer dev roadmap

Snapmaker U1 · OrcaSlicer fork · May 15 – Sep 23 2026 · click any card to expand
May 15, 2026 — session start
Setup
Architecture & repo decisions
Design goals, hardware constraints, repo selection
▾
Major Decision
  • wall[0] = 0.2mm outer nozzle; wall[1+] = 0.4mm inner nozzle
  • Min 2 walls if color or material is different; 1 wall allowed otherwise
  • Slope-compensated gap between wall[0] and wall[1] only
  • Accumulator sync: 0.4 nozzle fires when next 0.2 layer pushes accumulated height above 0.4 max
  • Color-to-nozzle priority: color match → smallest nozzle = outer → extruder 0 fallback
  • Color depth: min = nozzle diameter; thin section = bleed-through or 50/50 split
  • Per-patch nozzle override: global=YES follows mixed logic; global=NO single nozzle owns patch
  • Priority hierarchy locked: CL (color patch loops) > OW (outer wall) > IW (inner wall)
  • Started on OrcaSlicer-FullSpectrum fork, later pivoted to Snapmaker Orca due to cleaner Filament for Features UI
  • FullSpectrum had resolved_model_config_for_tab stripping sparse_infill_filament — unfixable cleanly
  • VS2019 required · CMake 3.29 · Build script: build_and_run.bat · build.ps1 includes timing
  • Strawberry Perl in PATH causes CMake version conflict — fix: override PATH
  • DLL strategy: copy all from installed Snapmaker_Orca\ except Snapmaker_Orca.dll
  • PrintConfig.hpp must be UTF-8 (not ANSI) — has // -*- coding: utf-8 -*- on line 1; run encoding fix script after editing in VS2019
  • DO NOT run encoding conversion on PrintConfig.cpp — Chinese characters corrupt on ANSI→UTF-8
Phase 1 — config + pipeline scaffold (ALH=Adaptive Layer Height)
Phase 1a
New files — NozzleLayerPlanner, ColorDepthProcessor, NozzleVerifyDialog
Core logic classes, all building cleanly
▾
  • SyncPoint struct: z, accumulated_height, accumulated_layers, gap_offset, expanding, outer_wall_extruder
  • plan() consumes ALH layer heights, produces sync points
  • Binary search queries: sync_point_at(), outer_wall_extruder_at(), gap_offset_at()
  • apply_depth(): per-layer ClipperUtils offset — built but not yet correctly wired (see Phase 5)
  • detect_thin_sections(): stubbed · ThinSectionBehavior: BleedThrough | Split50_50
  • inward_offset(): uses scaled() for correct Clipper unit conversion
  • Shows T1–T4 nozzle sizes, material names, color swatches
  • Verify button wires to MainFrame print button gate · update_extruders() rebuilds on reslice
Milestone
  • All 3 files registered in CMakeLists and building with zero errors
Phase 1b–d
PrintConfig fields + Pipeline hooks + Tab UI
New config fields, PrintObject, PerimeterGenerator, Multimaterial tab
▾
  • outer_wall_loops (coInt) · outer_wall_layer_height_max (coFloat) · outer_wall_seam_position (coEnum)
  • has_mixed_nozzle_sizes (coBool) · filament_color_depth (coFloat, placeholder)
  • Mixed Nozzle optgroup in Multimaterial tab: outer_wall_loops, outer_wall_layer_height_max, outer_wall_seam_position
Milestone
  • App launches · Multimaterial tab stable · Mixed Nozzle group visible · Slices without errors
Phase 2 — detection · May 16
Phase 2
PresetBundle auto-detection
has_mixed_nozzle_sizes computed automatically · outer_wall_loops clamped
▾
  • has_mixed_nozzle_sizes computed at end of full_fff_config(): any nozzle differs from values[0] by > 1e-4 → mixed=true
  • Never user-set — always derived at config assembly time
  • outer_wall_loops clamped to wall_loops when mixed (null-checked)
Milestone
  • Mixed nozzle auto-detected · outer_wall_loops clamped at slice time
Phase 3 — Repo pivot + NozzleVerifyDialog + print gate — May 16–17
Phase 3a
Fork from Snapmaker Orca instead of FullSpectrum
Cleaner base, Filament for Features already working
▾
Major Decision
  • FullSpectrum: unresolvable resolved_model_config_for_tab filtering — sparse_infill_filament couldn't show in Multimaterial tab
  • Snapmaker Orca is the actual target hardware — cleaner starting point
  • DLL workaround: use installed Snapmaker_Orca DLLs except Snapmaker_Orca.dll → saved as %USERPROFILE%\SnapmakerOrcaDLLs\
Phase 3b
NozzleVerifyDialog fully wired + print gate
Dialog shows after slice, print button gated until verify
▾
  • Mixed nozzle detection enabled in on_slicing_completed()
  • Filament color read from full_config() filament_colour vector (hex alpha stripped); stored by value to avoid dangling ptr
  • update_extruders() called on re-slice
  • get_enable_print_status(): nozzle verify gate added · get_enable_slice_status(): gate NOT added
Milestone
  • Dialog shows T1–T4 with nozzle sizes, material names, filament colors · Print gated until Verify
Phase 4 — OW/IW toolpath split + UI + per-nozzle line width — May 17 ✅ (OW=Outer Wall, IW=Inner Wall)
Phase 4a
inner_wall_filament field + UI
New extruder selector for inner wall, dropdown registered
▾
  • inner_wall_filament (coInt): gui_type=i_enum_open, min=1, default=1 · wall_loops label → "All walls" · wall_filament label → "Outer wall"
  • Added to Filament for Features group · registered to dynamic_filament_list_1_based · added to toggle_line loop
  • fdm_process_U1.json: "inner_wall_filament":"2"
Milestone
  • Inner wall dropdown shows extruder list · default extruder 2
Phase 4b–c
PrintRegion toolpath routing + GCode.cpp perimeter split
frExternalPerimeter → wall_filament · frPerimeter → inner_wall_filament
▾
  • extruder(): frExternalPerimeter → wall_filament; frPerimeter → inner_wall_filament
  • Only add inner_wall_filament when erPerimeter entities exist in this layer — prevents empty tool changes at cone tips
  • If PERIMETERS and inner/outer filaments differ and can_sort(): erExternalPerimeter → outer wall extruder; erPerimeter → inner wall extruder
  • Push directly into reg.perimeters — avoids owning temporary collections (heap corruption fix)
Milestone
  • Outer wall white (extruder 1), inner wall yellow (extruder 2) · No crashes
Phase 4d–f
OW>1, per-nozzle line width, UI polish
outer_wall_loops drives loop tagging · line widths rescaled per extruder nozzle diameter
▾
  • classic path: is_external = loop.depth < std::max(1, outer_wall_loops)
  • Arachne path: is_external = (int)extrusion->inset_idx < std::max(1, outer_wall_loops)
  • PrintRegion.cpp flow(): ratio = config_width / nozzle[0]; rescaled = ratio × actual_nozzle_diameter
  • fdm_process_U1.json: all line widths converted to percentages
  • outer_wall_loops label turns red when value > wall_loops (distinct from orange "modified" state)
  • U1 nozzle diameters: sync dialog removed; each extruder writes nozzle_diameter[i] independently
Milestone
  • Color swatches match sidebar · Each nozzle independently settable · outer_wall_loops label validation works
Phase 5 — Color patch pipeline — May 18–28 ✅ Complete
Phase 5a
Color patch — convex + concave surfaces working ✅
Committed ba3d32bc68 — single red loop on painted face, inner core correct
▾
  • Cube flat face: 1 red line on painted face only ✅
  • Sphere convex curved face: correct ✅
  • Torus inner hole (concave): correct single arc ✅ — fixed by building full_model from region slices (layer.lslices empty at segmentation time)
  • Adjacent painted faces same extruder: continuous red, no white seam ✅
  • Color patch loops UI slider in MMU gizmo panel ✅
  • GCode verified: T3 prints correct loops per layer ✅
  • Layer.hpp: color_patch_regions (vector) — shell strip per extruder per layer
  • PrintObjectSlice.cpp apply_mm_segmentation(): shell_strip = intersection(full_model_boundary_strip, stolen_expanded); inner core returned to base region
  • PerimeterGenerator: loop_number overridden to patch_loops-1; is_color_patch suppresses infill
  • color_patch_loops default: {1,1,1,1} for 4-head U1
Phase 5b
Color patch pipeline — complete ✅
All CL values, all surface types, per-object settings, Original mode verified
▾
  • Original mode: G-code output identical to stock OrcaSlicer — verified by G-code diff ✅
  • Color Patch mode: N outer loops in painted color; inner loops + infill use base filament ✅
  • Full wrap, all CL values: CL=1 through 10+ correct ✅
  • Partial face, all CL values: CL=1 through 10+ correct including odd CL ✅
  • Mixed nozzle sizes: each painted extruder uses its own flow values for loop width ✅
  • Per-object CL: each object on plate has independent CL values per extruder ✅
  • Infill suppression: no infill inside color patch zone — only CL loops print ✅
  • Multiple painted colors: T2, T3, T4 with different CL on same object works ✅
  • Project persistence: per-object CL settings save/load with 3MF ✅
  • T1 (black) = base material, wall_filament of model region
  • T2/T3/T4 = painted colors — users paint onto T1 body
  • color_patch_enabled[ext_idx]=false → Original mode (pass-through to stock pipeline)
  • color_patch_enabled[ext_idx]=true + color_patch_loops[ext_idx] > 0 → Color Patch mode
  • color_patch_loops default changed to {0,0,0,0} — Original mode is now the default
Milestone
Phase 5c
Architecture — final implementation
Key files, per-object CL flow, loop_width formula, config propagation
▾
  • color_patch_loops: coInts, default {0,0,0,0} in GCodeConfig
  • color_patch_enabled: coBools, default {false,false,false,false} in GCodeConfig
  • Both added to posSlice invalidation (Print.cpp) and posPerimeters invalidation (PrintObject.cpp)
  • Gate: if (cp_enabled && patch_loops > 0) — FOS pipeline only when both true
  • Per-object read: reads from model_object->config first, falls back to global print()->config()
  • loop_width = ext_width/2 + (CL>1 ? ext_sp2 : 0) + (CL>2 ? (CL-2)×perim_sp : 0) + perim_width/2
  • Uses target_lr (painted extruder's region) for flow values — supports mixed nozzle sizes
  • shell_strip stored in color_patch_regions[ext_idx] and color_patch_loops_effective[ext_idx]
  • mine subtraction: removes only shell_strip (not full stolen) — T1 keeps inner area
  • color_patch_regions: vector — shell strips per extruder
  • color_patch_loops_effective: vector — resolved per-object CL values per extruder
  • loop_number = patch_loops-1 set after all adjustments (overrides alternate_extra_wall etc.)
  • last overridden with color_patch_regions[wall_ext] clipped to current surface
  • offset_ex (not offset2_ex) for inner loop offsets — prevents thin wedge collapse
  • Gap detection skipped for color patch regions (is_cp_region_gap)
  • Infill suppressed for color patch regions (is_cp_region)
  • All CL loops get erExternalPerimeter role via cp_loops lambda
  • Forces process_classic (not Arachne) for color patch regions
  • inner_wall_filament added to painted region config — was missing, caused black inner loops
  • cfg.wall_filament, cfg.inner_wall_filament, cfg.solid_infill_filament, cfg.sparse_infill_filament all set to painted_extruder_id
  • Original button (left): sets color_patch_enabled[ext_idx]=false in model_object->config
  • Color Patch button (right): sets color_patch_enabled[ext_idx]=true, ensures color_patch_loops > 0
  • CL slider reads/writes color_patch_loops[ext_idx] in model_object->config
  • on_config_change must pass full preset config — partial config does NOT propagate correctly
  • Re-slice triggered via wxGetApp().plater()->update()
Phase 6 — App rename & branding — May 28 ✅
Phase 6
Renamed to FOrcaSlicer — Flexible OrcaSlicer + Fork-a-Slicer
Exe, DLL, installer, icon, web UI, splash, README all updated · v2.3.2-fos.1 released
▾
Major Decision
  • version.inc: SLIC3R_APP_NAME "FOrcaSlicer" · SLIC3R_APP_KEY must stay "Snapmaker_Orca" — translation .mo files are named Snapmaker_Orca.mo, changing it crashes the app
  • src/CMakeLists.txt: OUTPUT_NAME "FOrcaSlicer" (exe) · OUTPUT_NAME "FOrcaSlicer-core" (DLL) — DLL named -core to avoid CMake linker collision with exe base name
  • src/Snapmaker_Orca_app_msvc.cpp: loads FOrcaSlicer-core.dll
  • src/slic3r/GUI/Plater.cpp + GUI_App.cpp: title bar updated · startup wizard skipped (requires Snapmaker login)
  • installer.nsi: all references updated · VIProductVersion "2.3.2.1" (Windows resource requires integers only)
  • src/FOrcaSlicer.ico: 7-size ICO from FOrcaSlicer_Icon.png
  • resources/web + images: splash_logo.svg, logo.png, flutter_web title, guide welcome text all updated
  • Version: 2.3.2-fos.1 — based on Snapmaker OrcaSlicer commit 48c601c3b1 (their unreleased 2.3.2 dev branch)
  • Version regex in version.inc parses only X.X.X — the -fos.1 suffix is safely ignored at runtime
  • Build: cmake --build . --config Release --target ALL_BUILD -- -m
  • Install: cmake --build . --config Release --target INSTALL -- -m
  • Installer: makensis.exe /DVERSION=2.3.2-fos.1 installer.nsi
  • Portable: Compress-Archive -Path build\FOrcaSlicer\* -DestinationPath FOrcaSlicer_Windows_Portable_V2.3.2-fos.1.zip
  • PerimeterGenerator.cpp must be saved as UTF-8 (no BOM) with LF line endings — encoding checker fails with exit code -2 otherwise
Milestone
  • GitHub release v2.3.2 published · FOrcaSlicer_Windows_Installer_V2.3.2-fos.1.exe + Portable zip
Phase 7 — Color patch top/bottom surfaces — May 28–30 ✅ Complete
Phase 7a
Color patch top/bottom solid surfaces — design & iterations
Extend color patch to painted top/bottom faces — solid infill in painted color
▾
Major Decision
  • Side walls: CL loops only (shell_strip) — existing behavior unchanged
  • Top/bottom layers where painted region ends: painted extruder gets full stolen area, slices in original mode (natural loops + solid infill)
  • Detection: check if object top/bottom shell zone boundary coincides with where painted region ends — single intersection check per layer
  • Base extruder: subtracts full stolen on top/bottom layers; subtracts only shell_strip on wall layers
  • discover_vertical_shells staircasing: if painted extruder dst uses full stolen for top/bottom, discover_vertical_shells propagates larger area downward into wall layers → staircase artifact. Fix: painted extruder dst always uses shell_strip; solid infill comes from fill_expolygons being set to full exposed area
  • fill_expolygons clipping: fill_surfaces are clipped by fill_expolygons in Layer.cpp multi-region path. If fill_expolygons is only shell_strip, solid infill gets clipped away. Fix: for top/bottom CP layers, dst gets exposed top/bottom portion of stolen so fill_expolygons covers full top face
  • Exposed area split: for layers where painted region spans top face AND side face (crossing an edge), stolen is split — exposed portion gets full dst; side portion gets shell_strip only
  • CL slider re-slice fix: wxGetApp().plater()->update() alone doesn't mark object dirty. Fix: also call notify_instance_update(obj_idx, 0) + post_event(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)
  • ❌ Detecting top/bottom via top_shell_layers / bottom_shell_layers config alone → false positives on partial side patches
  • ❌ Area/shape consistency check across layers → too slow, OOM errors in parallel loop
  • ❌ Scan loop up/down from current layer → same OOM risk; replaced with single boundary intersection check
  • fos_near_obj_top = (layer_id >= total_layers - top_shells)
  • fos_near_obj_bottom = (layer_id < bot_shells)
  • If near boundary: check if stolen intersects object boundary at that boundary layer
  • Split stolen into exposed vs side portions using segmentation data of layer above/below
Phase 7b
Final state — shipped as v2.3.2-fos.1
Wall layers + top/bottom layers behave correctly · known limitations documented
▾
  • Painted extruder gets shell_strip → PerimeterGenerator generates CL loops only
  • color_patch_regions stores shell_strip for PerimeterGenerator
  • Base extruder subtracts shell_strip from mine → keeps inner painted area
  • Painted extruder gets exposed portion of stolen as dst → fill_expolygons covers full top/bottom area
  • color_patch_regions NOT populated → PerimeterGenerator runs in original mode (natural loops + solid infill)
  • color_patch_is_top_bottom flag → PerimeterGenerator suppresses sparse infill, allows solid infill
  • Base extruder subtracts full segmented.expolygons from mine → gives up full painted zone
  • PrintObjectSlice.cpp: color patch pipeline, top/bottom detection, mine subtraction, dst assignment
  • PerimeterGenerator.cpp: infill suppression for CP regions, top/bottom solid infill, top_fills guard
  • PerimeterGenerator.hpp + Layer.hpp: color_patch_is_top_bottom pointer/vector added
  • LayerRegion.cpp: passes color_patch_is_top_bottom to PerimeterGenerator
  • Curved surfaces (sphere, cone, cylinder): color patch behaves as original wedge method — regression cause unknown, not investigated; lower priority for U1 flat-faced use cases
  • UI sync: occasionally requires toggling Original → Color Patch after painting fresh object; low frequency, simple workaround
  • Top/bottom shell staircase near boundaries: same as stock OrcaSlicer multi-material discover_vertical_shells propagation — not a regression, accepted
Milestone
Phase 7c
CL slider / mode button re-slice fix — May 30 ✅
Two root causes found and fixed — config timestamp + invalidation path
▾
  • ModelObject::config.set_key_value() does not bump the config timestamp → PrintApply.cpp sees no change → returns APPLY_STATUS_UNCHANGED → no re-slice triggered
  • color_patch_loops and color_patch_enabled are stored in ModelObject::config (per-object DynamicConfig) but are not fields of PrintObjectConfig → even when timestamp changed, object_config_from_model_object never included them in the diff passed to invalidate_state_by_config_options
  • GLGizmoMmuSegmentation.cpp: call mo->config.touch() after every set_key_value for color_patch keys — 5 locations: Original button, Color Patch button ×2, CL slider, drag input
  • PrintApply.cpp: when object_config_changed is true, manually check if color_patch_loops or color_patch_enabled changed in per-object DynamicConfig and append them to the diff before calling invalidate_state_by_config_options
  • PrintObject.cpp: changed color_patch keys invalidation from posPerimeters to posSlice — perimeters-only invalidation was returning false when already invalidated, preventing re-slice
  • GLGizmoMmuSegmentation.cpp · PrintApply.cpp · PrintObject.cpp
Milestone
  • CL slider and mode button changes now reliably trigger re-slice
Phase 7d
Mixed nozzle + color patch hotfix — May 30 ✅
Three fixes shipped in v2.3.2-fos.1
▾
  • has_mixed_nozzle_sizes flag was defined but never computed — always false
  • Added computation in normalize_fdm_1(): iterates nozzle_diameter values, sets flag true if any differ from the first
  • This activates the Phase 2 code path in PerimeterGenerator that reads outer_wall_loops for mixed nozzle geometry
  • For color patch regions with CL=1 (loop_number=0), i0_half_width was using perimeter_spacing/2 — for large nozzles (0.6/0.8mm) this was too large, inset exceeded shell_strip width → empty offsets → missing color patch
  • Fix: use ext_perimeter_width/2 for CL=1, perimeter_spacing/2 for CL≥2. Condition: (is_cp_region && loop_number > 0)
  • Color Patch mode is meaningless when selected painting extruder is the OW extruder — would just replicate OW behavior
  • Guard: compares m_selected_extruder_idx against wall_filament-1 from print config. If match: auto-switches to Original mode, Color Patch button visually disabled, tooltip explains why
  • Note: ImGui::BeginDisabled not available in this ImGui version — used style color override + && !is_ow_extruder condition instead
  • Occasional color patch sync issue on fresh objects (pre-existing) — toggle Original → Color Patch to fix
  • Mixed nozzle + color patch with multiple feature extruders (OW/IW/infill all different) not yet fully validated — treat as separate workflows for now
Milestone
  • All three fixes shipped in v2.3.2-fos.1
Phase 8 — Foreign preset crash fixes + mixed nozzle polish — May 31 ✅ · v2.3.2-fos.2 released
Phase 8a
Foreign preset crash fixes — 7 issues resolved
Fresh install with Bambu/generic presets no longer crashes · system preset auto-sync disabled
▾
  • Fresh install downloads 2.3.14 presets from Snapmaker server — incompatible with FOrcaSlicer 2.3.2 codebase
  • FOrcaSlicer-specific config options missing from foreign presets → null pointer crashes when UI reads them
  • Symptom: clicking Multimaterial tab crashes with Access violation in DynamicConfig::opt_int() on foreign presets
  • Preset.cpp Preset::normalize(): add defaults for outer_wall_loops, outer_wall_layer_height_max, outer_wall_seam_position, color_patch_loops, color_patch_enabled, inner_wall_filament before handle_legacy_sla()
  • Tab.cpp TabPrint::reload_config(): same defaults added at start before Tab::reload_config()
  • OptionsGroup.cpp get_config_value() + get_config_value2(): null guards added for all coInt/coBool/coInts/coBools/coEnum/coEnums cases — returns 0/false instead of crashing
  • Symptom: adding Snapmaker U1 crashes in Sidebar::on_filaments_change() with access violation on choices.back()
  • Root cause: choices vector empty when called before sidebar combo boxes initialized
  • Fix: int last_selection = choices.empty() ? 0 : choices.back()->GetSelection()
  • Symptom: clicking paint gizmo with no object selected crashes on notify_instance_update
  • Fix: wrap all 4 FOS-added notify_instance_update blocks with null check on mo_notify before accessing model objects
  • Symptom: slicing fails with "Line width too small (skin_infill_line_width)" on 0.2mm nozzle second launch
  • Root cause: validation check extrusion_width_min <= layer_height triggers when both are 0.2mm — <= should be <
  • Fix: extrusion_width_min < layer_height in validate_extrusion_width lambda
  • Symptom: Unknown option exception: internal_solid_infill_acceleration fatal crash on startup
  • Root cause: option used in GCode.cpp and Print.cpp but never registered; also copy-paste bug gave skeleton_infill_line_width the wrong label/tooltip
  • Fix: register internal_solid_infill_acceleration as separate coFloatOrPercent entry; restore correct label/tooltip for skeleton_infill_line_width
  • sync_system_preset default changed from true to false — prevents downloading incompatible 2.3.14 presets on fresh install
  • Shortcut renamed from "Snapmaker Orca.lnk" to "FOrcaSlicer.lnk"
Milestone
  • Fresh install with any printer preset no longer crashes · system preset auto-sync disabled by default
Phase 8b
Mixed nozzle + color patch polish
SLIC3R_APP_KEY rename · inner_wall_filament fix · CL=1 large nozzle refinement
▾
  • Files: src/common_func/common_func.hpp + version.inc
  • App data now at %APPDATA%\FOrcaSlicer\ instead of %APPDATA%\Snapmaker_Orca\
  • All locale .mo files already copied to FOrcaSlicer.mo — no action needed
  • Pre-install step: copy Snapmaker_Orca.mo → FOrcaSlicer.mo for all locales before making installer
  • Missing def->mode = comAdvanced and def->set_default_value(new ConfigOptionInt(1)) — IW dropdown rendered incorrectly on first launch
  • Added both to match wall_filament definition
  • Refined fix from Phase 7d: i0_half_width for CL=1 color patch now uses ext_perimeter_spacing/2 (not ext_perimeter_width/2)
  • Spacing is slightly less than width — gives single CL=1 loop enough room in shell_strip for large nozzles (0.6mm, 0.8mm) at all layer heights
  • Condition: (is_cp_region && loop_number > 0) ? perimeter_spacing/2 : (is_cp_region ? ext_perimeter_spacing/2 : ext_perimeter_width/2)
  • Color patch FlowErrorNegativeSpacing with mixed nozzle sizes (e.g. T1=0.2mm, T3=0.6mm) — root cause not yet diagnosed; look in PrintObjectSlice.cpp shell_strip calculation and LayerRegion.cpp flow setup
  • IW dropdown may show incorrectly on absolute first launch — clicking refreshes it; root cause is dynamic_filament_list_1_based not yet populated when tab widget first created
  • outer_wall_layer_height_max field exists in UI but NozzleLayerPlanner accumulator logic not yet implemented — field has no effect on slicing
Phase 8c
top_surface_line_width .3mf load fix + v2.3.2-fos.2 release
Percentage line widths loading as absolute mm from saved .3mf · fos.2 ships all Phase 8 fixes
▾
  • Symptom: top_surface_line_width loading as 105mm instead of 105% when reopening a saved .3mf file
  • Root cause: percentage flag not preserved when line width values are serialized/deserialized from .3mf — value stored as float, % marker lost
  • Color patch (when CL=1) seam artifacts at arc endpoints when seam position is nearest or aligned — use random seam to avoid
  • Top/bottom painted face boundary follows stock OrcaSlicer shell propagation — bisector/normal separation planned for future
  • Mixed nozzle Phase 2 (separate perimeter generator per nozzle) not yet implemented — line widths use absolute mm in presets
  • IW dropdown may display incorrectly on very first launch — clicking refreshes correctly
  • Accumulator sync for IW max layer height not yet implemented
Milestone
  • v2.3.2-fos.2 released · FOrcaSlicer_Windows_Installer_V2.3.2-fos.2.exe + Portable zip
Phase 9 — Nozzle panel redesign + mixed nozzle spacing + stability — Jun 3 · v2.3.2-fos.3/fos.4
Phase 9a
Mixed nozzle OW/IW spacing fix + flow clamp + stability
Correct OW-to-IW transition spacing · Flow.cpp crash prevention · null guards
▾
  • OW loops now use ext_perimeter_spacing, IW loops use perimeter_spacing
  • Correct transition spacing at OW-to-IW boundary: 0.5 × (ext_perimeter_spacing + perimeter_spacing)
  • Fix only activates when wall_filament != inner_wall_filament (fos_ow_iw_split flag)
  • with_spacing() now clamps instead of throws when width < height
  • Prevents crash with color patch + mixed nozzle at higher layer heights
  • top_surface_line_width fixed to "105%" in source — was "105" (no % marker)
  • Note: percentage-based line widths break mixed nozzle flow calculation — all U1 process preset line widths kept as absolute mm (correct for mixed nozzle where perimeter generator runs in OW nozzle context)
  • Tab.cpp: outer_wall_loops vs wall_loops color check now guards against null config options
  • OptionsGroup.cpp: additional null guards for coInt case in get_config_value
  • Tab.cpp: outer_wall_layer_height_max option line and toggle commented out — pending accumulator sync implementation
Milestone
  • v2.3.2-fos.3 released with spacing fix and flow clamp
Phase 9b
Nozzle diameter panel redesign (fos.4)
2-column grid UI · mixed mode toggle · auto-detect · PRP refresh chain
▾
Major Decision
  • Printer Preset = PTP (Printer Type Profile) · Process Preset = PRP (Process Recipe Profile)
  • Replaced notebook tabs with 2-column grid matching filament panel style
  • Mixed mode toggle (SwitchButton, default OFF) — auto-detects mixed mode on PTP load if nozzle diameters differ
  • Color bar per row: 0.2mm=white, 0.4mm=10% gray, 0.6mm=20% gray, 0.8mm=30% gray · label format: "N: X.Xmm"
  • Process preset info note added above PRP dropdown — "Process presets are filtered by Nozzle 1 diameter. The layer height value you set determines your actual sliced result."
  • Changing any nozzle → confirm dialog (Sync/Cancel) → all nozzles sync to selected diameter → switch to matching system preset → PRP refreshes
  • Each nozzle independent — OW nozzle change updates inherits on custom PTP → PRP refreshes
  • Turning off mixed with differing diameters → confirm → sync all to Nozzle 1 → switch system preset
  • update_nozzle_settings(switch_machine=true) → reads OW nozzle idx from wall_filament → updates inherits → update_compatible(Always) → CallAfter → update_presets + load_current_preset
  • is_compatible_with_parent_printer() checks active_printer.preset.inherits() against compatible_printers list
  • Custom PTPs need correct inherits: "Snapmaker U1 (X.X nozzle)" based on OW nozzle diameter
  • PRP filtered by Nozzle 1 diameter regardless of which nozzle is assigned as OW — deferred until accumulator layer height sync implemented
  • Dark mode: nozzle color bars (white/gray scale) not tested — may need color inversion
Milestone
  • v2.3.2-fos.4 released · installer.nsi VIProductVersion 2.3.2.4
Phase 10 — OW nozzle → model color sync + painting erase warning — Jun 4 · v2.3.2-fos.5
Phase 10a
Nozzle diameter title icon
nozzle_diameter.svg added · ScalableButton wired in Plater.cpp
▾
  • Added nozzle_diameter.svg to resources/images/ — grey top arc, green side lines, outer green-stroked ellipse, inner green-filled ellipse representing nozzle tip
  • SVG: width="16" height="16" viewBox="0 0 16 16", inline attributes, stroke-width="0.9", no CorelDRAW boilerplate
  • Plater.cpp: uncommented nozzle_icon ScalableButton, updated icon key to "nozzle_diameter", wired into nozzle_title_sizer
Phase 10b
OW nozzle → model preview color sync
3D viewport and paint gizmo now reflect OW nozzle color assignment
▾
  • GL volume color: vol->extruder_id → filament_colour[extruder_id-1]; extruder_id always 1 for unpainted objects
  • simple_render (shells/thumbnails after slicing) hardcoded model_volume->extruder_id() as base color index
  • Paint gizmo ebt_colors[0] (base color for unpainted faces) also used mv->extruder_id()-1
  • Key design decision: do NOT set mo->config["extruder"] — breaks slicing by overriding per-feature filament assignments in object_config_from_model_object. Color override is purely visual.
  • Tab.cpp on_value_change: when wall_filament changes, CallAfter patches vol->extruder_id directly on all non-modifier GL volumes → update_volumes_colors_by_extruder(). Does NOT touch mo->config
  • GLCanvas3D.cpp reload_scene: after update_volumes_colors_by_extruder(), re-reads wall_filament and re-applies extruder_id override if OW > 1 — ensures color persists across every reload_scene
  • Tab.cpp · GLCanvas3D.cpp · Plater.cpp · resources/images/nozzle_diameter.svg
Milestone
  • v2.3.2-fos.5 released · VIProductVersion 2.3.2.5
Phase 10c
Multi-material painting erase warning on OW change
Prompt to erase MMU painting when OW nozzle changed · currently commented out pending testing
▾
  • When wall_filament changes: check mv->is_mm_painted() across all objects
  • If painted: MessageDialog — "Changing the Outer Wall nozzle will erase all multi-material painting on all objects."
  • Yes: mmu_segmentation_facets.reset() on all model part volumes → plater()->update()
  • No: read old value from get_selected_preset().config, revert via m_config_manipulation.apply(), return early — dropdown snaps back
  • Currently commented out — more testing needed before enabling
Phase 11 — OW color override + right drag rotate + startup fixes — Jun 4 · v2.3.2-fos.6
Phase 11a
OW color override — complete fix across all render paths
3DScene.cpp core fix · paint gizmo base color · thumbnail render · data_changed tracking
▾
  • simple_render (shells/thumbnails) still hardcoded extruder_id() as base color
  • Paint gizmo ebt_colors[0] used mv->extruder_id()-1, not OW extruder
  • 3DScene.cpp update_colors_by_extruder: reads wall_filament from config, uses OW extruder index for all model volumes when OW > 1
  • 3DScene.cpp simple_render: added ow_extruder parameter; idx==0 base color uses OW extruder when OW > 1
  • 3DScene.cpp render / render_with_outline: pass OW extruder to simple_render
  • GLCanvas3D.cpp render_thumbnail_internal: pass OW extruder to simple_render (both picking and non-picking paths)
  • GLGizmoMmuSegmentation.cpp init_model_triangle_selectors: ebt_colors[0] uses OW extruder color as base
  • GLGizmoMmuSegmentation.cpp update_triangle_selectors_colors + data_changed: static last_ow_ext_idx tracks wall_filament changes, triggers color update when changed
Milestone
  • Model color, thumbnails, and paint gizmo base color all correctly reflect OW nozzle assignment
Phase 11b
Right mouse drag rotates view + startup + PRP save fix
Right drag → rotate · mixed mode auto-detect on startup · PRP refresh after save
▾
  • is_camera_rotate: added evt.RightIsDown() — right drag now rotates same as left drag
  • is_camera_pan: removed right drag — pan is now middle button only
  • load_current_presets called update_nozzle_settings() without switch_machine=true — mixed mode auto-detect never fired on relaunch
  • Fix: update_nozzle_settings() → update_nozzle_settings(true)
  • After save_preset, PRP stayed on wrong nozzle until PTP manually re-selected
  • Fix: after update_presets_from_to in save_preset, call sidebar().update_nozzle_settings(true) when m_type == TYPE_PRINTER
Milestone
  • v2.3.2-fos.6 released · VIProductVersion 2.3.2.6
Phase 12 — Nozzle verify panel + mouse config + GCode legend — Jun 5 · v2.3.2-fos.7
Phase 12a
Nozzle verification integrated into GCode legend panel
Floating dialog replaced with inline panel in Filament legend · Print button gate preserved
▾
Major Decision
  • After slicing with mixed nozzles, a "Nozzle Verification" section appears at top of Filament legend panel (above filament table)
  • 2-row grid: Nozzle 1–N labels on top, diameter values with color-coded rectangles below (0.2mm=white, 0.4mm=10% grey, 0.6mm=20% grey, 0.8mm=30% grey)
  • Green "Verify nozzle sizes" button gates Print button until clicked → turns grey "[OK]" state
  • Re-slicing resets button back to green "Verify nozzle sizes"
  • Floating NozzleVerifyDialog commented out (preserved for future reference)
  • GCodeViewer.cpp — FOS nozzle verify block in case EViewType::ColorPrint
  • Plater.cpp — verify_nozzle_sizes(), is_nozzle_verify_required(), is_nozzle_verified(), reset on reslice
  • MainFrame.cpp — reset_nozzle_verified(), set_nozzle_verified_only()
Phase 12b
Mouse drag button assignment in Preferences + GCode legend defaults
Settings → General: per-button rotate/pan/none · Filament view default · OW first in Line Type
▾
Major Decision
  • Settings → General (below Use free camera): 3-row table — Left drag / Middle drag / Right drag, each with radio buttons: Rotate | Pan | Not assigned
  • Defaults: Left=Rotate, Middle=Pan, Right=Rotate
  • Config keys: mouse_left_btn_fn, mouse_middle_btn_fn, mouse_right_btn_fn (values: "rotate" | "pan" | "none")
  • GLCanvas3D.cpp is_camera_rotate + is_camera_pan read new keys
  • ColorPrint moved to first in view_type_items list
  • m_view_type default changed to EViewType::ColorPrint
  • After sort_remove_duplicates(m_roles), erExternalPerimeter and erPerimeter are swapped so OW appears before IW
Milestone
  • v2.3.2-fos.7 released · VIProductVersion 2.3.2.7
Phase 13 — Per-nozzle FLP (Filament Preset) filtering for mixed nozzle — Jun 7–8 · v2.3.2-fos.8 / fos.8.1
Phase 13a
Per-nozzle filament profile filtering — correct volumetric speed per slot
Slot 3/4 (0.2mm) now auto-selects 0.2mm FLP · 1.6mm³/s instead of 12mm³/s
▾
Major Decision
  • PresetComboBoxes.cpp FLP filter used nozzle_diameter[0] for all slots
  • Preset.cpp update_compatible_internal only marked FLPs compatible via parent printer inheritance — 0.2mm FLPs incompatible when printer inherits from 0.4mm parent
  • PresetBundle.cpp update_compatible auto-selection ignored nozzle diameter per slot
  • Alias collision: Generic PLA and Generic PLA @U1 0.2 nozzle share alias "Generic PLA" — map key collision caused wrong preset to display/select
  • update_compatible_internal: FOS block marks filament presets compatible if compatible_printers matches any nozzle diameter in mixed nozzle printer config
  • Restricted to TYPE_FILAMENT only · uses vector copy of cp->values to avoid pointer invalidation
  • update_compatible: unconditional FOS block after select_other_filament_if_incompatible gate
  • Iterates all filament slots, checks compatible_printers against slot's nozzle diameter
  • On mismatch: first_compatible lambda scores by nozzle match (required) + same alias (+1000) + same material type (+10)
  • Per-slot display filter in PlaterPresetComboBox::update(): filters by slot nozzle diameter AND printer model
  • get_preset_name override returns full preset name in mixed nozzle mode
  • Appends @U1 X.X nozzle suffix to presets lacking nozzle suffix — consistent naming
Milestone
  • Slot 1/2 (0.4mm): Generic PLA @U1 0.4 nozzle, 12mm³/s ✓ · Slot 3/4 (0.2mm): auto-selects Generic PLA @U1 0.2 nozzle, 1.6mm³/s ✓ · v2.3.2-fos.8 released
Phase 13b
Hotfix — FLP dropdown lockup + crash on preset reselection · v2.3.2-fos.8.1
fos.8 get_preset_name fabricated names broke 0.4mm slot dropdown · nullptr crashes fixed
▾
  • fos.8 get_preset_name fabricated "Generic PLA @U1 0.4 nozzle" — no actual preset with that name exists in bundle; broke system_presets map key matching → drop_down stuck, ComboBox unable to reopen. 0.2mm slots unaffected because "Generic PLA @U1 0.2 nozzle" is a real preset name.
  • DynamicFilamentList::update and DynamicFilamentList1Based::update called find_preset()->get_filament_type() without null guard — nullptr crash during preset selection state transition
  • combo->update() called synchronously during selection event in on_select_preset — potential dropdown state corruption
  • Null guard in DynamicFilamentList::update and DynamicFilamentList1Based::update — checks find_preset() result before calling get_filament_type()
  • Deferred combo->update() in on_select_preset via wxTheApp->CallAfter to avoid corrupting dropdown state during selection event
  • Simplified get_preset_name: returns preset.name directly in mixed nozzle mode — no fabricated suffix; 0.4mm base presets shown as-is (e.g. "Generic PLA"), non-0.4mm already have nozzle suffix in actual name
  • FOS suffix-stripping in switch_to_tab: if display name not found in bundle, strips @U1 X.X nozzle via regex before alias lookup
Milestone
  • FLP dropdown on 0.4mm slots reopens correctly · no crash on reselection, multimaterial tab, or slice · fos.8 per-nozzle filtering intact · v2.3.2-fos.8.1 released
Phase 13c — Inner wall filament + outer wall loops save/load fix — Jul 12 · v2.3.2-fos.8.2
Phase 13c
Fix — inner wall filament + outer wall loops not surviving project save/load · v2.3.2-fos.8.2
Both FOS keys missing from s_Preset_print_options · dropped by apply_only on project reload
▾
Major Decision
  • v2.3.2-fos.8.2 designated the initial public release of FOrcaSlicer
  • Inner wall filament: saved assignment (e.g. N3) came back as the Outer wall nozzle on reload — exported G-code routed inner perimeters to the OW tool
  • Outer wall loops: saved quantity discarded on reload, silently reverted to default
  • Both applied correctly within a session — loss only visible after close/reopen, or via the two keys missing from a reloaded project's G-code config header
  • inner_wall_filament and outer_wall_loops were defined in PrintConfig.cpp with set_key_value defaults in Preset.cpp, but neither was listed in s_Preset_print_options — the registry of valid print-preset keys
  • On project load PresetCollection::load_external_preset rebuilds the config via apply_only(combined_config, print_options) — keys absent from print_options are filtered out; both keys were written on save but dropped before reaching the preset
  • wall_filament / sparse_infill_filament / solid_infill_filament unaffected because already registered — only the two FOS-added keys were missing, which is why the bug looked selective
  • Added "outer_wall_loops" to s_Preset_print_options (after "wall_loops") and "inner_wall_filament" (after "wall_filament")
  • installer.nsi: VIProductVersion bumped to 2.3.2.8 (stale at 2.3.2.7 since fos.7) · no slicing code changed
  • Thick internal bridges: internal bridge extruded at nozzle_diameter × sqrt(bridge_flow) with no clamp against layer height — extreme under mixed nozzles (0.8mm nozzle on 0.1mm layer → 0.8mm-tall extrusion, 8× layer height, overlapping sparse infill beneath). Upstream Orca behavior, not FOS-specific — stock Orca with uniform 0.8mm nozzles at 0.24mm layers shows the same. Workaround: disable Thick internal bridges when solid-infill nozzle ≫ layer height; layer-height-aware clamp under consideration
Milestone
  • IW filament survives save/load (saved IW=N3 reloads as N3, G-code routes inner perimeters to that tool) ✓ · outer wall loops survives save/load ✓ · both keys now in reloaded G-code config header ✓ · both regain reset-dot and preset-baseline tracking ✓ · v2.3.2-fos.8.2 released
Phase 13d — Vendor profile refresh + duplicate profile cleanup — Jul 13 · v2.3.2-fos.8.3
Phase 13d
Fix — corrected Snapmaker profiles never reached existing installs · v2.3.2-fos.8.3
Stale bundle version froze cached profiles at the broken 105% state · 20 duplicate-name profiles · FOrcaSlicer branding in About
▾
  • Same project file produced different line widths on two computers — upgraded installs showed a mix of percentages and mm in the Quality tab, including a bare "105" top surface width (105 mm, no % sign)
  • Only 0.4mm nozzle presets affected; 0.2/0.6/0.8 clean · fresh installs also clean, which made it hard to pin down
  • Not cosmetic: line widths are coFloatOrPercent with ratio_over = nozzle_diameter, so a stored 105% resolves to a different physical width per nozzle (0.21mm on 0.2, 0.84mm on 0.8) — under mixed nozzles this silently changes what gets printed
  • U1 process presets went through three revisions: df0a7e9d58 (mm → 105%/110%, top_surface became bare 105), 03a404bda3 (repaired 105 → 105%), 7b5c73e1af (everything back to absolute mm) — corrected mm values shipped in resources/profiles/ ever since
  • PresetUpdater::check_installed_vendor_profiles only refreshes %APPDATA%/FOrcaSlicer/system/<Vendor>/ when the resource bundle declares a newer version — Snapmaker.json sat at "02.02.46.02" through every FOS profile edit, so the check never fired and machines kept whatever profiles they first installed (the df0a7e9d58 state, frozen)
  • Every profile fix was faithfully packaged into the installer, then silently ignored on upgrade
  • 20 process profiles declared the same "name" key as a real sibling → nondeterministic preset binding: 19 "* copy.json" files (0.2/0.6/0.8 presets) + "0.20 Standard @Snapmaker U1 (0.4 nozzle)_old.json"
  • The _old.json is the 0.4-nozzle collision — exactly why 0.4 misbehaved; an older thinner revision, not referenced by the Snapmaker.json index (prior cleanups eeebb38a47 / 710caf2ac1 never shipped — dev branch only)
  • Snapmaker.json bundle version 02.02.46.02 → 02.02.47.00 — Semver::parse is 3-component (4th field invisible to comparison), so bumping .02 → .03 would have done nothing; moving the patch field (46 → 47) makes 2.2.46 < 2.2.47 true and triggers the refresh · also keeps FOS ahead of Snapmaker's official 02.02.46.x so their online updater won't overwrite it
  • Deleted the 20 duplicate-name profiles — install_bundles_rsrc calls remove_all() on the vendor folder before recopying, so the bump both delivers corrected profiles and sweeps stale files off existing machines
  • libslic3r.h SLIC3R_APP_FULL_NAME "Snapmaker Orca" → "FOrcaSlicer" — drives Help > About menu, About dialog title, error captions, MessageDialog titles; display-only (paths driven by SLIC3R_APP_KEY, already FOrcaSlicer)
  • common_func.hpp: added FOS_VERSION "2.3.2-fos.8.3" — kept separate from Snapmaker_VERSION deliberately (that macro is written into 3mf metadata, project settings, user_backup folder name; changing it would break project round-trips and orphan backups)
  • AboutDialog.cpp: version line reads "FOrcaSlicer 2.3.2-fos.8.3" with "Based on Snapmaker Orca 2.3.2 / Orca Slicer" beneath · fixed mojibake © — raw U+00A9 in a narrow literal decoded via current locale (GBK → CJK glyph); now pure ASCII, decoded explicitly via wxString::FromUTF8
  • No slicing code changed · upgrade note: corrected profiles apply automatically on first launch; customized user presets untouched — only the system bundle under %APPDATA%\FOrcaSlicer\system\Snapmaker\ is replaced
Milestone
  • Upgrading to 8.3 refreshes the cached vendor bundle — all U1 line widths load as absolute mm on every nozzle ✓ · 20 duplicate-name profiles removed from existing installs ✓ · zero percentage line widths and zero duplicate names remain in the Snapmaker profile tree ✓ · same project yields identical line widths across machines ✓ · Help > About reads "About FOrcaSlicer", dialog shows FOrcaSlicer 2.3.2-fos.8.3 with correct © ✓ · v2.3.2-fos.8.3 released
Phase 13e — Support, tree support + prime tower were all sized for nozzle 1 — Jul 14 · v2.3.2-fos.8.4
Phase 13e
Fix — support, tree support and prime tower all computed geometry from nozzle 1 · v2.3.2-fos.8.4
Single theme: three features sized for nozzle 1 regardless of printing tool · no-op on uniform-nozzle machines
▾
  • Support on filament 2 of a 0.2/0.4/0.6/0.8 machine: slicer picks the right nozzle, then tells it to lay a 0.22mm line — nozzle 1's width; the 0.4mm tip asked for a bead thinner than itself
  • Prime tower worse: every tool wiped at 1.0mm and rammed at 2.0mm — the 0.2mm nozzle included, at 5× and 10× its own diameter
  • Not rounding errors — extrusions a nozzle physically cannot lay
  • Absolute line widths in a process preset are authored against nozzle 1 (the reference nozzle); any feature printed by a different tool must re-derive the width by ratio. PrintRegion::flow() has done this all along for frExternalPerimeter/frPerimeter/frInfill/frSolidInfill/frTopSolidInfill — but support roles aren't in that list, and support never passes through PrintRegion::flow() at all: it goes through free functions in Flow.cpp that pick the right nozzle then hand it an unadjusted width
  • Tree support wrong a second way: support_extrusion_width (sizes the tree base) was read from support_interface_filament's nozzle, not the base's · two further sites hardcoded nozzle_diameter.get_at(0), pinning branch spacing and collision resolution to nozzle 1 outright
  • Prime tower kept a single scalar and overwrote it: WipeTower2::m_perimeter_width assigned inside set_extruder(), called once per filament — last filament configured won by accident of iteration order (0.8 × 1.25 = 1.0mm for everyone); the code even states "all extruders are now assumed to have the same diameter" · meanwhile m_filpar[idx].nozzle_diameter was populated all along and never read
  • New fos_width_for_nozzle() — the nozzle-1 → printing-nozzle ratio rule, exported so support, SupportParameters and TreeSupport all derive widths identically instead of three different ways; percent widths pass through untouched (get_abs_value already ratios over the nozzle it's given) · support_material_flow, support_material_1st_layer_flow, support_material_interface_flow now route through it
  • SupportParameters: support_extrusion_width now comes from support_filament (was support_interface_filament), ratio-derived — it sizes the support base, so it was taking dimensions from the wrong tool
  • TreeSupport: two hardcoded nozzle_diameter.get_at(0) reads replaced with the support filament's nozzle, ratio-derived — these drive collision resolution and branch spacing; a tree printed by a 0.6mm tool was built to 0.2mm dimensions
  • Structure width (footprint, box margins, brim spacing, tower perimeter + sparse fill) bound to wipe_tower_filament — the tool that genuinely prints them (set_extruder marks it the only non-soluble one, so first_toolchange_to_nonsoluble lands finish_layer on it); previously whichever set_extruder call ran last
  • Wipe and ramming now extrude at each tool's own width and flow, from m_filpar[tool].nozzle_diameter
  • Depth planning follows: plan_toolchange() and save_on_last_wipe() reserve depth with the same per-tool widths — width and spacing must move together or the purge block over/under-fills and reserved depth stops matching emitted lines · ramming E is volumetric (ramming_speed × time / filament_area) so only line length changes, purged volume unaffected
  • Support/raft base, Support/raft interface and Wipe tower offer "Default" = whichever filament is already loaded — invalid under mixed nozzles and unfixable: support paths are generated once at slicing time with a single flow, but the tool isn't chosen until G-code export, where ToolOrdering reassigns the tool on already-generated extrusions and nothing re-renders them; a path built for a 0.2mm tip can be handed to a 0.8mm tip
  • When nozzle diameters differ: those three dropdowns show "Empty" instead of "Default", and the slicer refuses to slice until a filament is chosen, naming which dropdown is blank · deliberately NOT auto-filled with filament 1 — silently landing on nozzle 1 is precisely the bug being fixed · uniform-nozzle machines: "Default" behaves exactly as before
  • FOS_VERSION → 2.3.2-fos.8.4 · installer VIProductVersion 2.3.2.8 → 2.3.2.9 · upgrade note: mixed-nozzle users with support/prime tower asked to pick filaments on first slice; pre-8.4 projects may open with these blank and the slicer names which it needs
  • Support layer height still follows nozzle 1 — consistent with the 8.x rule (all nozzles follow nozzle 1's process settings), but a 0.8mm nozzle can be asked to print 0.1mm support layers; a layer-height clamp would be a new feature, not a fix — deferred
  • Ramming-to-wipe alignment: Y offsets aligning the ramming block to the first wipe line still use the tower's structure width — with per-tool widths can be off up to ~0.4mm; cosmetic, no effect on purge volume or tower geometry
Milestone
  • Verified in G-code (0.2/0.4/0.6/0.8, support base fil.3, interface fil.2, tower fil.2): support 0.22 → 0.66mm on 0.6 tool ✓ · interface 0.22 → 0.44mm on 0.4 tool ✓ · tower wipe 1.0×4 → 0.25/0.5/0.75/1.0 ✓ · ramming 2.0×4 → 0.5/1.0/1.5/2.0 ✓ · purge block stays inside tower wall ✓ · tree branch spacing scales with support nozzle ✓ · uniform-nozzle slices unchanged (0.6×4: same 0.62mm support, same 0.75/1.5 tower widths, same extrusion counts) ✓ · v2.3.2-fos.8.4 released
Phase 14 — Per-nozzle line width and speed — Jul 14 · v2.3.2-fos.8.5
Phase 14
Per-nozzle line width and speed · v2.3.2-fos.8.5
Each feature prints at the width and speed of the nozzle that actually prints it — not Nozzle 1 for everything · per-nozzle prime tower width · layer height guarded by smallest used nozzle
▾
  • On mixed-nozzle printers, each print feature now takes its line width and speed from the nozzle that actually prints it — set in Quality and Speed, per-nozzle tabs (Nozzle 1–4); assignment follows the Process filament dropdowns (outer wall, inner wall, infill, solid infill, support)
  • Line width: outer wall, inner wall, top surface, sparse infill, internal solid infill, support · Speed: outer wall, inner wall, small perimeter, sparse infill, internal solid infill, top surface, gap infill, ironing, support, support interface
  • Values typed in the Nozzle 2–4 tabs take effect immediately — no preset reload needed
  • Each nozzle gets a Prime tower line width field (Quality tab) — 0 for auto (1.25 × that nozzle's diameter), or set a value; every tool wipes and rams at its own width, tower walls/footprint use the wipe-tower filament's value
  • Previously the whole tower used a single width from whichever tool was configured last — a 0.2 nozzle could be laying 1.0mm tower lines
  • Layer height and initial layer height remain a single global setting, shown below the nozzle tabs — automatically limited to the range the smallest nozzle actually used can print (can't ask a 0.2mm tip to lay a 0.6mm layer); the limit follows assignments, so using only larger nozzles opens the range up
  • The limit counts the object's own filament too — if a layer-height limit looks too low, check the filament assigned to the object in the object list, not just the Process dropdowns
Milestone
  • Verified in G-code across mixed 0.2/0.4/0.6/0.8 setups and a uniform 0.6 regression — single-nozzle-size printers unchanged, output identical to before ✓ · not yet bed-tested — real-print reports wanted on mixed-nozzle models · v2.3.2-fos.8.5 released
Phase 14a — Hotfix: painted patch width + Nozzle 1 preset — Jul 17 · v2.3.2-fos.8.5.1
Phase 14a
Hotfix over 8.5 — per-nozzle width on painted patches + Nozzle 1 keeps its own preset · v2.3.2-fos.8.5.1
Two fixes, no new features
▾
  • On a mixed-nozzle printer, a surface assigned to a nozzle by painting (color patch / segmentation) now prints at that nozzle's line width — same as a surface assigned through the Process feature dropdowns
  • In 8.5, painted patches printed at the base region's width regardless of which nozzle laid them: a 0.2mm tip could be pushed to ~0.4mm and a 0.8mm tip held to ~0.4mm; feature-dropdown assignment (outer wall, inner wall, infill, solid infill) was unaffected — only painted regions. Restores the behavior that shipped before 8.5
  • After the fix, a painted 0.2/0.4/0.6/0.8 model lays roughly 0.22/0.42/0.62/0.82 per nozzle — occasional wider lines on the large nozzle are normal gap infill
  • Nozzle 1's process preset now follows Nozzle 1's own diameter · previously it was tied to whichever nozzle printed the outer wall: assigning the outer wall to a different nozzle — or painting a model so the outer-wall filament wasn't nozzle 1 — locked Nozzle 1's preset to that nozzle's diameter, and it would snap back on reload
  • Nozzle 1 now stays on its own preset regardless of the outer-wall assignment; nozzles 2–4 keep their own presets as before
Milestone
  • Single-nozzle-size printers unchanged, output identical to before ✓ · if you don't paint color patches or reassign the outer wall on a mixed-nozzle machine, these fixes change nothing · v2.3.2-fos.8.5.1 released
Phase 14b — Hotfix: crash when adding U1 PTP on a fresh install — Jul 19 · v2.3.2-fos.8.5.2
Phase 14b
Hotfix over 8.5.1 — crash when adding the Snapmaker U1 on a fresh install · v2.3.2-fos.8.5.2
Dangling raw pointers into a resized std::vector in the per-nozzle notebook · one crash fix, no new features
▾
  • On a fresh install, adding the Snapmaker U1 (mixed-nozzle PTP) crashed immediately — hard access violation, no dialog, no error message
  • Longstanding latent bug in the per-nozzle notebook, exposed only on the fresh-install path; independent of the 8.5.1 fixes
  • Stack: TabPrint::fos_reload_slot_config (Tab.cpp ~3517) → ConfigOptionsGroup::reload_config (OptionsGroup.cpp ~750) → get_config_value → crash at config.def() (~945)
  • Per-nozzle slot optgroups are built with raw pointers into the m_fos_slot_configs std::vector (&m_fos_slot_configs[n]) · the notebook build and fos_reload_slot_config call resize(nozzle_count) at three sites — when resize GROWS the vector it reallocates the buffer, dangling every optgroup's m_config; the next reload_config() reads the freed config and faults
  • Adding the U1 on a fresh install grows the slot vector (1 → 4) — that reallocation is the trigger; on an existing profile the vector is already sized, hence "fresh install only"
  • Ruled out (recorded so they aren't re-chased): the "contains incorrect keys: color_patch_enabled, inner_wall_filament..." log flood is BENIGN — process/object-scope keys correctly stripped from machine presets, not the crash · an initial null-guard on get_config_value's opt deref was a misread of the crashing line (the fault is the config access at 945, before any opt deref)
  • Tab.hpp: m_fos_slot_configs changed from std::vector to std::deque — deque keeps existing element addresses stable across resize/grow at the end, so the optgroup raw pointers never dangle; verified no contiguity assumption on the container (only single-element addresses, no .data()/.reserve()/.capacity()), so it's a drop-in and one change covers all three resize sites
  • OptionsGroup.cpp: null guard in get_config_value and get_config_value2 — if config.def()->get(opt_key) returns null, return empty instead of dereferencing; defensive hardening for a separate latent null-deref, NOT this crash
  • FOS_VERSION 2.3.2-fos.8.5.1 → 2.3.2-fos.8.5.2 · installer VIProductVersion 2.3.2.11 → 2.3.2.12 · everything from 8.5.1 unchanged
  • The release log truncates mid-write at a hard crash and carries no stack. Best: Visual Studio on the build machine — rename %APPDATA%\FOrcaSlicer aside to force a fresh config, run under the debugger with symbols, reproduce · WER local dumps (HKLM LocalDumps, DumpType=2) → .dmp opened in VS with the matching PDB · quick triage: Event Viewer → Application Error → faulting module + offset
Milestone
  • Reproduced on a fresh config (delete %APPDATA%\FOrcaSlicer, add U1 PTP) → hard crash with the stack above; after the deque fix + rebuild, same path → no crash, confirmed by user ✓ · v2.3.2-fos.8.5.2 released
Phase 14c — Hotfix: per-nozzle widths apply on PTP create — Jul 20 · v2.3.2-fos.8.5.3
Phase 14c
Hotfix over 8.5.2 — per-nozzle line widths now apply the moment a mixed-nozzle PTP is created · v2.3.2-fos.8.5.3
Lazy optgroup build meant the first slice used Nozzle 1's width until the Quality tab was opened · one fix, no new features
▾
  • On a mixed-nozzle printer, creating a new print-type profile (PTP) assigned each nozzle the correct process preset, but the slice still used Nozzle 1's line width for every nozzle until you opened the Quality tab (or re-picked a nozzle's process preset)
  • Painted color-patch surfaces showed the same thing — the painted nozzle's width didn't take effect until you visited Quality; explains the cross-machine difference where one install had visited Quality and the other hadn't
  • update_prp_nozzle_rows (ParamsPanel.cpp) auto-selects the correct per-nozzle PRP for each slot then calls fos_reload_slot_config(i) to resolve the fos_nozzle_*_line_width arrays — but fos_reload_slot_config bails early on m_fos_slot_optgroups[slot_idx].empty(), and the per-nozzle notebook optgroups build LAZILY, only when Quality is first opened
  • So on a freshly created PTP the slot configs never load; fos_resolve_nozzle_arrays keeps the arrays mirrored to slot 0 (Nozzle 1). Opening Quality builds the optgroups, the reload finally runs, and the widths snap correct — probe showed RESOLVE stuck at ow=0.220×4 (nd=0.2,0.4,0.6,0.8) until Quality was opened, then reaching 0.220,0.420,0.620,0.820
  • Ruled out: the s21 "N1 eviction" fix was NOT the mechanism — the probe showed Nozzle 1 / slot 0 correct throughout, never evicted; this is a different mechanism (PTP-create optgroup timing)
  • First fix removed the bail so the load+resolve run even with empty optgroups — fixed create but REGRESSED normal use: clicking a per-nozzle tab collapsed all lines to 0.2. The bail is load-bearing — during normal use the print tab is torn down and rebuilt constantly, firing fos_reload_slot_config(0) alone while slots 1..N are momentarily empty; the bail stops fos_resolve_nozzle_arrays running on that partial snapshot. Reverted in full
  • Lesson: the optgroup-empty bail is not just a UI guard — it protects the resolved arrays from single-slot resolves during tab teardown/rebuild churn. Any create-time populate must load the COMPLETE set first and resolve exactly once
  • New TabPrint::fos_populate_all_slots(bool mixed_active) — loads every slot config from its source (slot 0 from *m_config; slots 1..N-1 from each nozzle tab's stored selected_preset_name(), which survives optgroup teardown) then calls fos_resolve_nozzle_arrays() ONCE on the complete set; no optgroup dependency, no UI reload · uniform mode mirrors N1 · a per-slot change-guard preserves slot hand-edits
  • ParamsPanel.cpp: after the per-slot auto-select loop in update_prp_nozzle_rows, call fos_populate_all_slots(mixed_active) — the create/diameter-change path · fos_reload_slot_config's optgroup-empty bail left intact so the churn path stays protected
  • FOS_VERSION 2.3.2-fos.8.5.2 → 2.3.2-fos.8.5.3 · installer VIProductVersion 2.3.2.12 → 2.3.2.13 · everything from 8.5.2/8.5.1 unchanged
Milestone
  • G-code (cube_build_3.gcode) toolpath ;WIDTH: tags by active tool — T0=0.22, T1=0.45, T2=0.62, T3 ~0.82; each nozzle extrudes its own width, config block fos_nozzle_outer_wall_line_width = 0.22,0.42,0.62,0.82 · create is correct with NO Quality visit; Nozzle 2 tab-click no longer collapses; uniform mode mirrors N1 correctly ✓ · v2.3.2-fos.8.5.3 released
Phase 14d — Hotfix: global Filament-for-Features regression + "Global" label + CJK/i18n — Jul 21 · v2.3.2-fos.8.5.4
Phase 14d
Hotfix over 8.5.3 — global Filament-for-Features slicing regression + per-object "Global" label + imgui CJK + zh_CN pass · v2.3.2-fos.8.5.4
Forced object extruder=1 clobbered every per-feature assignment · four fixes, no new features
▾
  • Objects were stored with a forced extruder=1 · PrintObject apply_to_print_region_config step-1 fill does, in effect: if (extruder != 0) { sparse_infill = solid_infill = wall = inner_wall = extruder; } — so a non-zero object extruder OVERWRITES every global per-feature assignment with that one filament
  • With OW=1/IW=2/infill=3/solid=4 set globally, all four collapsed to Filament 1 and the prime tower vanished (only one filament in use)
  • Fix: keep object extruder = 0 (unassigned) so the clobber branch is skipped and features resolve from the global assignment · Model.cpp (3 spots ConfigOptionInt(1) → (0)), GUI_ObjectList.cpp (update_filament_values_for_items + add-mesh path back to 0) · also restored OrcaSlicer's per-object model (object display color driven by object-level filament only; misleading per-feature outer-wall color preview removed)
  • extruder=0 previously displayed "default", which was misleading — it's the fallback/global state (features fall back to the global assignment), not literally a default · now reads "Global" (全局), reusing the existing msgid and matching the Global/Objects mode toggle
  • Six sites, all // FOS: tagged: wxExtensions.cpp get_default_extruder_color_icon (shared icon covers editor dropdown row + modifier/layer icons), ExtraRenderers.cpp dropdown fallback row, ObjectDataViewModel.cpp object/modifier/layer display strings · for modifier parts / layer ranges 0 means "inherit parent" but it's one shared icon, so all read "Global"
  • Garbled button: ImGuiWrapper::button() only has wxString overloads; imgui.button(_u8L("...")) passed a UTF-8 std::string, which hit the implicit wxString(std::string) ANSI/Latin-1 ctor → translated CJK bytes mis-decoded → mojibake (imgui.title takes std::string directly, so the adjacent title looked fine) · fix: _u8L → _L on both buttons ("Verify nozzle sizes", "Nozzle sizes verified")
  • English nozzle labels: the Nozzle 1..N header used raw sprintf("Nozzle %d") with no translation → fixed to wxString::Format(_L("Nozzle %d")) → 出口 %d
  • General trap (recorded): any translated _u8L passed to a wxString-only sink mojibakes via the implicit std::string → wxString ANSI ctor · rule: _L for wxString sinks, _u8L only for std::string/char* sinks — only the nozzle-verify overlay was audited this round
  • Broad zh_CN pass: 耗材丝 → 耗材 (137 incl. a 耗材丝丝 double), default → 默认 (was 缺省), Global → 全局, Filament for Features → 特征对应的耗材, Wipe tower → 擦拭塔, Ooze prevention → 预防渗出, added Preheat delta temperature → 预热温差 (msgid was never extracted to the .po), stripped leftover English "Skirt"/"Brim" from field labels (Brim header → 加固边沿); zh_TW untouched
  • Pipeline root cause (probe-confirmed): the app loads AddCatalog(SLIC3R_APP_KEY) = FOrcaSlicer.mo, but gettext_po_to_mo emitted Snapmaker_Orca.mo (wrong name) and called bare msgfmt (not on Windows PATH → target always failed) — so the runtime zh_CN catalog was frozen at a hand-made May-17 .mo and .po edits never reached the app
  • Fix: gettext_po_to_mo now calls bundled tools/msgfmt.exe and emits ${SLIC3R_APP_KEY}.mo = FOrcaSlicer.mo; sibling gettext_merge_po_with_pot uses tools/msgmerge.exe · verified building the gettext_po_to_mo target regenerates FOrcaSlicer.mo from the .po via the official pipeline · all *.mo gitignored, catalog now reproducible from source (was a manual artifact that vanished on clean build)
Milestone
  • Global Filament-for-Features resolves correctly (OW=1/IW=2/infill=3/solid=4 no longer collapse, prime tower returns) ✓ · per-object no-filament cell reads "Global"/全局 ✓ · nozzle-verify overlay button and Nozzle 1–4 headers display correct Chinese ✓ · zh_CN translations survive a clean build ✓ · single-nozzle-size printers unaffected · FOS_VERSION → 2.3.2-fos.8.5.4, installer VIProductVersion 2.3.2.13 → 2.3.2.14 · v2.3.2-fos.8.5.4 released
Phase 14e — Outer-wall object identity + Default-filament cleanup + PRP scaling — Jul 22 · v2.3.2-fos.8.5.5
Phase 14e
An object's filament is now its outer wall · Default/Global fallback removed · PRP panel DPI scaling fixed · v2.3.2-fos.8.5.5
Objects always carry a concrete filament — no more invisible default
▾
  • An object's filament is now defined by its outer wall (wall_filament) end to end — the per-object Filament column and the 3D object color both show the outer-wall filament (what you see on the print), not a separate object "default"; the old "Global" label is gone
  • Every entry point stays in sync and drives the same value: right-click menu, inline Filament dropdown, Object Table dropdown, outer-wall filament selector, 3D preview · one shared feature group is the source of truth; the step-1 object-extruder clobber in apply_to_print_region_config is deleted, features resolve from the step-2 copy loop
  • Right-click "Change Default Filament" → "Unify Object Filaments" — sets outer wall, inner wall, sparse infill and solid infill of the selected object(s) to one filament in a single action (the "print this whole object on filament N" shortcut); the Object Table dropdown does the same · both menu strings translated to Simplified Chinese
  • Support base/interface and the wipe tower keep their own filament controls — on mixed-nozzle printers they still must be a concrete filament (gate unchanged)
  • Object-list Fila. column no longer offers a "Global" row for objects/model parts — they list filaments 1..N and default to filament 1; parameter modifiers and layer ranges keep the inherit row (0 = inherit is still meaningful there)
  • Filament for Features dropdowns (walls, inner walls, sparse infill, solid infill) list filaments only; a feature still holding 0 is printed on filament 1 · the four feature filaments now default 1 / min 1 (were 0/0), and clamp_feature_extruder stays as the crash-guard for legacy/hand-edited configs holding 0
  • Outer wall, inner wall, top surface, sparse infill, solid infill and support line-width tooltips now state that setting the value to 0 uses the Default line width (documents existing behavior so 0 reads as "inherit"); Chinese tooltips updated
  • On two monitors at different scaling (e.g. 100% + 150%), the Nozzle 2–4 PRP rows stayed frozen at build-time scale while Nozzle 1 tracked the current monitor — their combos, save/search buttons and row spacing looked oversized. Root cause: N2–N4 are TabPrintNozzle tabs that remove themselves from tabs_list and sit in no msw_rescale path · fix: new TabPrintNozzle::fos_rescale_row (rescales the owned combo/buttons/bitmaps/row-height only — the full Tab::msw_rescale is UB on nozzle tabs) plus a TabPrint::msw_rescale override for the per-nozzle notebook slot optgroups; no more toggling tabs to fix spacing
  • Also since 8.5.4: fixed a false "Too small line width" error that could block slicing a mixed-nozzle object at a tall layer height · FOS_VERSION → 2.3.2-fos.8.5.5, installer VIProductVersion 2.3.2.14 → 2.3.2.15
Milestone
  • Object identity is its outer wall across Fila column, 3D tint, menu, all dropdowns and preview ✓ · Default/Global row removed where objects/features carry a concrete filament ✓ · PRP rows and per-nozzle notebook tabs rescale with the current monitor ✓ · false too-small-width slice block fixed ✓ · single-nozzle-size printers unaffected · v2.3.2-fos.8.5.5 released
Phase 15 — First macOS build · cross-platform release — Jul 27 · v2.3.2-fos.8.5.6
Phase 15
First macOS build — universal DMG, rename finished on macOS, unified user data · v2.3.2-fos.8.5.6
No slicing behavior changed — Windows slicing output identical to 8.5.5
▾
Major Decision
  • v2.3.2-fos.8.5.6 is the first release with a macOS build — FOrcaSlicer is now cross-platform (Windows + macOS)
  • Ships a macOS DMG built from source in GitHub Actions — a universal binary (app, crash handler and Sentry library all carry x86_64 + arm64 slices), running natively on Intel and Apple Silicon; minimum macOS 12.0 (Monterey), tested on Intel and Apple Silicon (M4 Max, macOS 26)
  • Not signed or notarized (no Apple Developer certificate) — first launch is refused with "Apple cannot check it for malicious software"; clear quarantine once: xattr -dr com.apple.quarantine "/Applications/FOrcaSlicer.app", or System Settings > Privacy & Security > Open Anyway (the Control-click bypass was removed in macOS 15)
  • The 8.x rename covered the Windows app name/icon/exe; several macOS-only code paths were outside its scope and never exercised (no macOS build existed). Now all correct: app bundle + executable are FOrcaSlicer (not "Snapmaker Orca"); the FOrcaSlicer icon shows everywhere including the Dock tile (previously reverted to the Snapmaker icon while running); the language list is populated again — the mac build generated catalogs under the old name so the app found no FOrcaSlicer.mo and offered no languages, now all ~20 locales load
  • Several paths were still hardcoded to Snapmaker_Orca, so FOrcaSlicer read/wrote a mixture of its own directory and Snapmaker Orca's; every path now derives from the application key, so FOrcaSlicer is fully independent of any other Orca-family slicer installed alongside it
  • Now from FOrcaSlicer's own directory: profile/web version files read at startup, language/region detection (reads FOrcaSlicer.conf, was Snapmaker_Orca.conf), crash report data (FOrcaSlicer/SentryData) · Windows users: no action needed, no settings lost — presets/profiles were always in the FOrcaSlicer directory
  • Two GitHub Actions workflows: universal release build (deps matrix → universal build, DMG + dSYM) and a single-arch x86_64 fast-test · three CI defects fixed, each costing a failed run: pinned CMake 3.31.6 (brew yields CMake 4.x which drops cmake_minimum_required <3.5 compat); uninstall Homebrew zstd before any cache action (zstd removal mid-job changed the cache compression method so every lookup missed); compute the dep cache key once after checkout (a restored dep prefix mutated hashFiles() for the next restore) · required step order: Checkout → Remove zstd → Compute dep cache key → cache action → rest
  • Nozzle tabs after adding a U1 PTP: the per-nozzle notebook shows only one tab until you click away and back — cosmetic, presets created correctly
  • macOS dark mode on first launch: notebook and nozzle-diameter labels can render light-on-light until the system appearance is toggled — the app samples appearance before the window exists and doesn't re-check; cosmetic, macOS only
  • macOS builds are unsigned and unnotarized (see quarantine note)
Milestone
  • Universal DMG verified genuinely universal (CI audit: all three Mach-O files carry x86_64 + arm64; everything else statically linked) ✓ · launches natively on Intel and Apple Silicon (M4 Max, macOS 26) ✓ · clean Mac creates only ~/Library/Application Support/FOrcaSlicer/, no Snapmaker_Orca directory ✓ · Windows data unified, nothing written to Snapmaker_Orca ✓ · FOS_VERSION → 2.3.2-fos.8.5.6, installer VIProductVersion 2.3.2.15 → 2.3.2.16 · v2.3.2-fos.8.5.6 released with Windows installer, portable zip and universal macOS DMG
Phase 16 — Beta: per-nozzle presets beyond four nozzles — Jul 29 · v2.3.2-fos.8.5.7-beta.1
Phase 16 · beta
Pre-release — per-nozzle process presets no longer limited to four nozzles · v2.3.2-fos.8.5.7-beta.1
PRP rows and per-nozzle tabs now follow the printer's nozzle count, no upper bound · four-nozzle U1 slicing identical to 8.5.6
▾
  • The per-nozzle PRP rows and the per-nozzle tabs inside Quality > Line width and Speed were built for exactly four slots — a printer with more than four nozzles got four rows, and slots five and up silently fell back to Nozzle 1's values when slicing
  • The whole set now follows the printer preset's nozzle-diameter list with no upper bound: each slot has its own PRP dropdown filtered to that slot's nozzle diameter and resolves its own line widths and speeds into the slice; selecting a printer with fewer nozzles hides the extra rows rather than leaving them behind
  • The tab strips fixed their tab count when the page was first drawn — after adding a U1 preset only one tab appeared until you clicked away and back (the known limitation from 8.5.6), and changing to a printer with a different nozzle count left the old tab count in place. Both fixed: the strips rebuild as soon as the nozzle count changes
  • The About box reads "2.3.2-fos.8.5.7-beta" without the ".1" — the beta number lives in the tag and file names so later betas don't require a rebuild (expected, not a bug)
Milestone
  • Verified: U1 4-nozzle in software and on hardware · Prusa XL 5 tool heads and a custom 8-toolhead machine in software (PRP assignment, tab behavior, resolved widths/speeds in G-code) · macOS (Intel) tab fix confirmed · four-nozzle U1 slicing output identical to 8.5.6, no slicer code touched · v2.3.2-fos.8.5.7-beta.1 (pre-release) tagged
Phase 16a — Beta: preset-key save fix + update notifications + profile bundle — Aug 13 · v2.3.2-fos.8.5.7-beta.2
Phase 16a · beta
Pre-release — four settings could never be saved · update notification · Snapmaker bundle 02.02.55.02 · v2.3.2-fos.8.5.7-beta.2
Slicing otherwise unchanged from beta.1 · does NOT include the in-progress filament/nozzle mapping
▾
  • Four FOS options were defined but never registered to any preset type, so they were stripped on the next preset load and silently reverted to defaults: Color patch enabled + Color patch loops (filament), Outer wall seam position + Inner wall max layer height (process)
  • The same defect produced hundreds of "contains incorrect keys ... which were removed" log errors on every launch — one per preset, on FOS's own bundled profiles as well as saved ones (up to nine hundred per launch on a machine with many presets); the program was inserting the keys itself right after loading, then removing them and blaming the file · all four now round-trip and the log is clean · pre-fix projects load these at defaults until re-saved once (same as the 8.2 fix)
  • FOS now checks for new releases at startup and on demand · a beta-channel checkbox controls whether pre-releases are offered, "Skip this version" suppresses one version without turning checking off, the download button opens the release page in the browser (FOS never downloads or installs anything itself) · uses GitHub with a self-hosted fallback for networks that block GitHub · only helps from this version on — 8.5.6 and beta.1 have no update check so this one upgrade is manual · About box now reads the full "2.3.2-fos.8.5.7-beta.2" since the update check compares that string exactly
  • Brought up to date from 02.02.47.00: many filaments gained 0.2/0.6/0.8 per-nozzle variants alongside 0.4 (Generic/Snapmaker ABS + ASA, Generic PC, Support For PLA, PVA, PLA Silk/Wood/CF, TPU 90A + 95A HF), new filaments (PETG/PLA Translucent, PLA Glow/Marble/Full Spectrum), a rename map so upstream-renamed U1 presets (@U1 → @U1 0.4 nozzle) carry over, a G-code escaping fix, and recognition (store + preserve, not yet acted on) of filament_is_high_temperature
  • 20 stray duplicate-name files (19 "... copy.json" + one "..._old.json") removed from the bundle — the _old.json was a stale copy of 0.20 Standard @Snapmaker U1 (0.4 nozzle) with different prime-tower and missing quality settings · NOT removed from existing installs (FOS never deletes vanished profiles) — manual cleanup of copy.json/_old.json in %APPDATA%\FOrcaSlicer\system\Snapmaker\process\, or install fresh
Milestone
  • Verified: all four options round-trip on save/reload · color-patch slice (3 painted faces) · profile bundle loads clean, no preset errors on launch (macOS build pending at write time) · no slicer code modified · v2.3.2-fos.8.5.7-beta.2 (pre-release) tagged
Phase 17 — 8.6 release · filament-to-nozzle mapping + multi-material supply — Aug 23 · v2.3.2-fos.8.6.0
Phase 17
The 8.6 release — mixed nozzle printing that is honest about itself · v2.3.2-fos.8.6.0
Map any filament to any nozzle, slice each for the nozzle it prints through, refuse to slice when the combo can't physically work · supersedes both 8.5.7 betas
▾
Major Decision
  • Theme: mixed nozzle printing that is honest about itself — any filament to any nozzle, each sliced for the nozzle it actually prints through, and a hard refusal to slice when the combination cannot physically work; plus multi-material supply support (starting with multiACE) and a large performance fix affecting everyone
  • Breaks the old assumption that a filament prints on the nozzle with its own number (filament 3 → nozzle 3). Open the map from the nozzle panel and wire each filament to any nozzle by dragging between pins — more filaments than nozzles is fine
  • Each filament is sliced for its nozzle (line widths, speeds, flow all follow the mapped nozzle, not the index); dropdowns filter to presets matching the assigned nozzle diameter; unassigned filaments show unattached and slicing stops until wired · fresh start defaults to the obvious 1:1 map for as many nozzles as the printer has · the map is stored in the project (3mf), not the printer profile
  • Under Printer settings > Machine > Accessory: Supply system (multiACE; Sidecar listed, not implemented), Printer LAN IP:port, Mode (normal/multi/head, using multiACE's own vocabulary — mode decides how many filaments load per nozzle, a slicing input set before slicing), Supply units / Toolheads with a unit · "Read from printer" queries mode, unit count, unit-driven toolheads and fitted nozzles, shows the full picture and fills fields only after you confirm — never overwrites nozzle diameters
  • "Send to multiACE" (under the print dropdown) uploads the sliced file straight to the machine's inbox · exported G-code always carries the machine's physical nozzle diameters in the header (fos_physical_nozzle_diameter) so the supply system can match demand against fitted hardware · map pins labelled U#S# (unit/slot; a pin means a unit in multi mode, a slot in head mode); a stored assignment that no longer fits is kept and drawn red as N/A, not silently discarded
  • Filaments can be marked Translucent with a 1–99 Translucency percentage (Filament page; percentage greyed until marked) · used in two visual-only places: the filament-to-nozzle map draws translucent swatches over a checker background, and the sliced preview can draw them see-through via a Solid | Translucent switch (defaults to Solid each launch, appears only when a translucent filament is in use) — no effect on slicing or G-code
  • Filament colour dialog gains a HEX field (#RRGGBB or RRGGBB), two-way with the picker/swatch/HSL/RGB boxes; sits where the disabled "Define Custom Colours" button was · Windows standard dialog with the field added; macOS native picker already has hex
  • First layer line width now follows the nozzle — was a single value applied to every nozzle, so on a 0.2 + 0.8mm machine layer 1 extruded the same width through both; each preset's own first-layer width is now used for its nozzle including brim/skirt/support. Affected even the simplest 1:1 mapping — worth re-slicing anything printed on a mixed machine
  • Slicing stops when a used filament has no nozzle (previously it silently inherited nozzle 1's diameter/offsets) — the message names every unassigned filament and how it's used (painted, Filament-for-Features, object/part, height range, support, prime tower, custom-G-code change)
  • Slicing stops when map and hardware can't agree: no supply system → a filament must map to the nozzle that prints it or one of the same diameter; supply system without declared wiring → the sliced diameter must exist on some nozzle; wiring declared → additionally no more filaments may demand a diameter than the wiring can load at once (e.g. four filaments on one 0.2mm nozzle but only two units connected is refused with counts) · support and prime-tower filaments must be chosen explicitly on a mixed machine
  • A permanent repaint loop is gone — two tab strips added in the 8.5 line re-invalidated themselves from inside their own paint handler, giving 300–400 repaints/second sustained, burning a full CPU core from when the print-settings pages were built until the app closed (made project loading slow, worsened the longer the app stayed open). Idle CPU is now zero · very likely the cause if 8.5.6 hung or crawled opening 3mf files · the same change fixes those strips in dark mode
  • Project import no longer fights the UI — the progress callback fired far more often than the displayed percentage changed and each update yielded to the event loop; now updates at most ten times a second
  • Includes per-nozzle presets for any nozzle count (beta.1), the four-settings preset-key save fix, update notification and Snapmaker bundle 02.02.55.02 with 20 duplicate files removed (beta.2)
  • Saving a project with more filaments than nozzles corrupted the printer on reopen (20 filaments on a 4-nozzle machine came back as a 20-nozzle printer, supply settings lost) — now records the printer as configured · filament-to-nozzle map no longer empty on fresh start · preset filtering no longer assumes filament number = nozzle number · nozzle panel no longer rebuilds repeatedly (flicker) · map window: theme changes refresh it, LAN IP field wide enough for a full address+port
  • From beta.2 with a supply system configured: re-enter the printer LAN IP once — beta.2 stored it per-extruder and it carries over as a joined string (127.0.0.1:7126,127.0.0.1:7126,...) that looks plausible but fails at send with "curl: URL using bad/illegal format"; retyping clears it. The supply-system dropdown resets to None on upgrade (expected — re-select)
  • Projects saved before this release carry one nozzle per filament — re-save once from this version (the embedded map reads correctly either way) · pre-four-settings-fix projects load those four at defaults until re-saved · duplicate profiles are not removed from existing installs (manual cleanup or fresh install)
Milestone
  • Filament-to-nozzle mapping, multiACE supply support, translucent filaments, hex colour entry, three mixed-nozzle safety guards, the repaint-loop fix, and both betas all shipped in 8.6.0 · only the U1 exercised on hardware (5- and 8-toolhead verified in software) · Windows installer + portable zip + universal macOS DMG · v2.3.2-fos.8.6.0 released
Phase 17a — Patch: profile fixes (0.18 preset + 27 stray duplicates) — Sep 1 · v2.3.2-fos.8.6.1
Phase 17a
Patch — bundled-profile fixes, both applied automatically on first launch · v2.3.2-fos.8.6.1
8.6.0 unchanged · the manual-cleanup instruction from 8.6.0 is retired
▾
  • 0.18 Standard @Snapmaker U1 (0.6 nozzle) inherited a correct 0.18mm layer height then overrode it back to 0.25mm — a preset named 0.18 printing 39% thicker than its name (changing layer count, time, strength, finish); its five siblings (0.24/0.30/0.30 Strength/0.36/0.42) carry no such override, marking it a defect · upstream defect inherited from Snapmaker's own v2.3.5 · after upgrade the preset prints at 0.18mm (longer print, finer finish for the same settings)
  • 27 profile files deleted from the project were still written by the installer (19 process presets ending in " copy.json"/"_old.json", 7 renamed filament profiles) — the packaging step only ever added/updated files, never removed one, so every build carried them forward; showed as duplicate-looking entries on fresh installs as well as upgrades · the packaged payload is now rebuilt from scratch and verified file-by-file against the source tree (10696 files, none missing/extra/differing)
  • Snapmaker bundle version → 02.02.55.03 (this is what lets existing installs take both fixes on first launch) · macOS build tooling reports per-stage/total build time, consistent staging dir name, dep cache accounts for local patches · a GUI media-state value held as a plain int for clean clang compile, OpenVDB patched for clang 16+ (no behavior change)
Milestone
  • Nothing to do by hand — on first launch the bundled profile folder is refreshed (corrected 0.18 arrives, 27 stray files removed), saved user presets untouched · one caveat: a user preset derived from the 0.18 one keeps its own stored layer height (including 0.25mm if inherited from the defect) — open it once and check · v2.3.2-fos.8.6.1 released
Phase 17b — Patch: filament choices vanished after changing a nozzle diameter — Sep 1 · v2.3.2-fos.8.6.2
Phase 17b
Patch — filament choices vanished after changing a non-outer-wall nozzle diameter · v2.3.2-fos.8.6.2
Slicer fix, not profiles · no settings file touched
▾
  • On a mixed-nozzle printer, changing a nozzle's diameter only re-evaluated which filaments fit if you changed the outer-wall nozzle; change any other and the list stayed filtered against the old diameter
  • Nothing looked wrong until the next rebuild (opening the filament-to-nozzle map + OK): the slot's dropdown collapsed to the single selected preset, new-diameter filaments unreachable and old-diameter ones correctly gone — both halves vanished at once, reading as "all my filaments are missing" · affects Mixed mode with more than one nozzle size; nothing saved was changed or lost
  • The nozzle-diameter handler called update_compatible() only when the changed nozzle was the outer-wall one, so compatibility was never recomputed for other nozzles; a duplicated copy ran synchronously before the new diameter was written to the printer config, so even the outer-wall nozzle had one path reading the old value · the refresh now runs for every nozzle and only after the new diameter is in place, and the duplicated block is gone · which parent profile the printer inherits still follows the outer-wall nozzle alone (that decides which process presets apply — not a per-nozzle question)
Milestone
  • Diameter changes on any nozzle re-filter filaments correctly, after the value is in place ✓ · bundled profile version unchanged from 8.6.1, settings folder not rewritten · v2.3.2-fos.8.6.2 released
Phase 17c — Nozzle panel: session verification, Synced/Desynced, layer-height limits + 4 fixes + zh — Sep 2 · v2.3.2-fos.8.6.3
Phase 17c
Nozzle-panel additions + four fixes + completed Chinese translation · v2.3.2-fos.8.6.3
Three additions to the nozzle panel and printer settings
▾
  • Verified until restart — a checkbox below Verify; tick it, click Verify, and you're not asked again until restart; switching printer profile clears it (verification is per-profile)
  • Synced / Desynced toggle (was "Mixed") — per-nozzle mode was previously inferred from diameters alone, so four identical nozzles couldn't have separate process presets; Desynced turns it on regardless, stored in the printer profile so it survives restart and printer switch
  • Layer-height limits follow the nozzle — entering a nozzle diameter in Printer Settings fills that nozzle's min/max layer height (still editable); narrowing passes silently, widening past the nozzle's range asks once
  • Syncing nozzles could overwrite your own printer profile — switching to Synced and choosing Save at the unsaved-changes prompt wrote the synced diameters into your profile (a 0.2/0.4/0.4/0.6 profile came back as four 0.2 under the same name); now your profile is left untouched, the slicer switches to the matching stock profile and names which one first
  • The Synced/Desynced toggle could show the wrong state after saving a preset, discarding changes, or editing a diameter · per-nozzle process presets showed the globally selected preset name (incl. the modified marker) rather than their own — binding and slicing were correct, only the display was wrong · layer-height limits kept the previous nozzle's values when the diameter changed by anything other than typing
  • The zh catalogue hadn't been rebuilt since Jul 25, so later translations never reached the app — fixed · 173 newly translated strings (filament-to-nozzle map, nozzle verification, filament pool, multi-material supply pages, parameter tabs, new warnings) · nozzle term now consistently 挤出口 · corrected 其它线宽 / 其它速度 / 外墙线数 / 预热温度差值 · Preferences mouse-button rows (Left/Middle/Right drag) translated
Milestone
  • Session verification, Synced/Desynced independent of diameter, and auto layer-height limits added; the four nozzle-panel/limit defects fixed; Chinese catalogue rebuilt and complete · v2.3.2-fos.8.6.3 released (Windows installer + portable, universal macOS DMG)
Phase 17d — Choose which nozzles print support + prime tower wall + per-nozzle PRP diameter fix — Sep 4 · v2.3.2-fos.8.6.4
Phase 17d
Choose which nozzles print support and the prime tower wall · per-nozzle PRP now follows diameter · v2.3.2-fos.8.6.4
One feature, one fix, 20 Chinese strings
▾
  • Support/raft base, Support/raft interface and Wipe tower wall each get a Custom entry at the top of their filament list — choosing it enables a nozzle list below (Base / Interface / Wipe tower wall nozzles), one row per physical nozzle + diameter; tick the allowed nozzles and the field reads back e.g. "1, 3 (0.4)"
  • The selection is over nozzles, not filaments, and works in both Synced and Desynced (built for the case of four same-diameter nozzles where one carries something you'd rather not spend on support)
  • All nozzles in one selection must share a diameter — support is generated with a single flow before the tool is chosen, and the tower wall prints at one width; ticking a nozzle greys out every different-diameter nozzle, and slicing refuses a selection that breaks this (naming the nozzles) · your choice outranks tool-change efficiency: a chosen nozzle is used every layer incl. first, and a tower-wall nozzle unused elsewhere still prints the tower
  • "Wipe tower" renamed to "Wipe tower wall" (the setting only ever controlled the wall); the two slicing messages reworded to match
  • With Desynced on, changing a nozzle's diameter updated its filament list but left that nozzle's process preset on the old diameter until a printer preset was saved (Nozzle 1 → 0.6 filtered filaments to 0.6 while the preset stayed at 0.4) · now every nozzle (Nozzle 1 included) re-picks a matching process preset as soon as its diameter changes, and an earlier per-nozzle choice no longer outranks the current diameter · a note now appears above the Nozzle 1 row in Desynced mode: only Nozzle 1's process preset affects layer height
  • 20 new strings: the three nozzle-selection controls + tooltips, the Custom row in each picker, the nozzle rows, and the six slicing messages that refuse an invalid selection · terms follow the catalogue — 挤出口, 自定义, 擦塔外墙, 支撑/筏层主体, 支撑/筏层界面 · other languages fall back to English
Milestone
  • Per-nozzle support/tower-wall nozzle selection shipped (diameter-consistent, Synced or Desynced, honored on every layer); per-nozzle PRP now tracks the current diameter for every nozzle · v2.3.2-fos.8.6.4 released (Windows installer + portable, universal macOS DMG)
Phase 17e — Patch: object filament identity (7 fixes) + color patch crash + false tower-wall requests — Sep 10 · v2.3.2-fos.8.6.5
Phase 17e
Patch — how an object's filament is set and shown, one crash, three false prime-tower requests · v2.3.2-fos.8.6.5
No new features · one bug report traced to a family of defects
▾
  • One report — unify a cube to filament 4, open Color Painting, the cube shows filament 1 — was one visible symptom of a family left behind when object identity moved to the object's own outer-wall setting (Jul 22): four controls set an object's filament and they disagreed with each other
  • Color Painting read the outer-wall filament from global settings only; it now resolves part → object → global like everything else, so the gizmo, the 3D scene and the Multimaterial tab agree
  • The object list's Fila. dropdown set only the outer wall, leaving IW, sparse and solid infill on the old filament (an outer skin in one color over an interior in another) — it now sets the whole group, matching Unify Object Filaments and the Object/part setting table
  • A pick in that dropdown did nothing until Enter, a click elsewhere or a view move · Filament for Features rows in the Multimaterial tab showed the previous filament until the object was reselected
  • Slicing could crash inside color patch processing depending on where patched layers fell (a use-after-free) — looked intermittent and model-dependent · in the same place, the downward-facing-surface check had never run, so a patch bottom can now slice differently than before (intended behavior finally taking effect)
  • A color patch painted in the object's own outer-wall filament collapsed the object to a single perimeter and turned sparse infill solid — patch and body were matched by filament number, not identity; such a patch is now invisible and nothing else changes
  • Desynced on a single-diameter machine demanded a tower-wall nozzle selection — Desynced means per-nozzle settings, not different diameters · a single-filament plate counted as needing a tower because several filaments were loaded · an unused filament could appear in a plate's filament list (a stray second color in the tower preview) · a machine with genuinely different diameters still asks, correctly
  • The plater still draws a prime-tower placeholder on single-filament plates although none is generated — cosmetic, deferred
Milestone
  • All four filament controls, the painting gizmo and the Multimaterial tab agree on an object's filament; color patch crash and own-filament patch defect fixed; tower-wall requests only when a tower is actually printed · v2.3.2-fos.8.6.5 released (Windows installer + portable, universal macOS DMG)
Phase 17f — Linux AppImage + Align to First, Distribute First to Last, Nest + support interface Z distance — Sep 23 · v2.3.2-fos.8.6.6
Phase 17f
First Linux build · three multi-object layout tools · automatic support Z distance · v2.3.2-fos.8.6.6
Right-click a multi-selection in Prepare · 35 new Chinese strings
▾
  • First Linux release — a single self-contained AppImage built on Ubuntu 22.04 (glibc 2.35+, needs FUSE 2 / libfuse2) · a very minimal system may need mkdir -p ~/.config once before first launch
  • Getting there fixed three build defects that meant nobody had built this fork's AppImage since the app rename: a cmake 3.22 empty-argument bug that configured the wrong source directory, the app command set to two different values in two scopes (packaging looked for a binary that did not exist yet the build reported success), and a missing 192px icon
  • Select two or more objects, right-click → Align to First → Top / Left / Bottom / Right — the first-selected object stays put and the others line up with its edge (Top = back of the plate from above) · no collision check: objects in the same row or column can overlap
  • Three or more objects — the first and last selected stay in place, the ones between are spaced evenly: left / horizontal center / right / top / vertical center / bottom space the chosen edges or centers; horizontal and vertical spacing equalize the gaps · both tools follow Ctrl-click order in the 3D view or object list; a box selection uses object-list order
  • Nest → Close (2mm gap) / Loose (3.5mm gap) packs the selected objects onto the plate, moving them and turning them in 90° steps; unselected objects stay exactly where they are and are packed around; whatever does not fit goes to a new plate
  • Nests by the real outline seen from above, not a bounding box, so a pocket in a C or U shape can take other objects · counts support and brim — exact from the last slice (tree support often spreads well past the model at the base), otherwise estimated from the model and settings with a notification to slice and nest again · an object with no overhangs gets no support room
  • Keeps objects at least 3.5 mm from the plate edge so the spiral-lift boundary warning does not fire · tries many packing orders within a few seconds and keeps the best
  • When the support interface filament is a different material type from the outer wall (e.g. PETG interface under PLA), Top and Bottom Z distance under Support → Advanced are set to 0 and a message shows the previous values — a dissimilar interface only releases cleanly when it touches the part · two slots of the same material do not trigger it
  • 35 new strings: the three layout menus and their options, the Nest notification, and the support Z distance prompt · terms follow the catalogue — 对齐到首个, 首尾之间均匀分布, 排样, 紧密/宽松, 加固边沿, 支撑面
  • Nest places objects one at a time and never goes back to rearrange earlier ones — a very full plate can leave room a person could still use by hand · support/brim room is exact only after slicing
  • Linux has no in-app update check yet — AppImage users check Releases themselves
  • The Z distance adjustment is not reached from the Unify menu or Object Table, and does not re-check when a filament's material type changes
Milestone
  • Linux joins Windows and macOS; multi-object Align to First, Distribute First to Last and support/brim-aware outline Nest shipped; support Z distance follows interface material · v2.3.2-fos.8.6.6 released (Windows installer + portable, universal macOS DMG, Linux AppImage)
Outstanding / TODO
TODO
Remaining items
Regression fix, cleanup, version bump, extended testing
▾
  • Color patch FlowErrorNegativeSpacing with mixed nozzle sizes — not yet diagnosed
  • Painting erase warning on OW change — implemented but commented out, pending testing
  • Nozzle 1's process preset drives global layer height by design — per-nozzle process presets now exist (Synced/Desynced, 8.6.3) and PRP filtering is implemented, but only Nozzle 1's PRP affects layer height (noted in the UI, 8.6.4); true per-nozzle layer height still pending accumulator sync
  • _u8L → wxString mojibake trap may exist wherever a translated _u8L is passed to a wxString-only sink — only the nozzle-verify overlay was audited (8.5.4)
  • Modifier/layer fallback icon reads "Global" though it semantically means "inherit parent" (shared icon) — revisit if per-type labels are wanted
  • Per-nozzle FLP — full architecture deferred: requires per-slot speed overrides in PRP (OW/IW/infill/top surface speeds per nozzle)
  • Curved surface color patch regression — verify sphere/torus/cone CL loops; if broken, bisect between 48c601c3b1 and current
  • Color patch CL=1 seam artifacts at arc endpoints (nearest/aligned seam) — workaround: use random seam
  • PRP filtering by actual OW nozzle — deferred until accumulator layer height sync implemented
  • Accumulator layer height sync (NozzleLayerPlanner) — not yet started
  • Drag-and-drop STL after fresh install fails — workaround: run OrcaSlicer once; fix: investigate installer.nsi shell registration
  • Thick internal bridges: layer-height-aware clamp on bridge extrusion height (upstream Orca behavior, extreme under mixed nozzles — see fos.8.2 known issue)
  • Support layer height clamp for large nozzles — support still follows nozzle 1's layer height; a 0.8mm nozzle can be asked to print 0.1mm support layers (new feature, deferred — see fos.8.4 known issue)
  • Ramming-to-wipe Y alignment uses tower structure width — up to ~0.4mm off with per-tool widths; cosmetic (see fos.8.4 known issue)
  • outer_wall_loops: no hard UI cap (label turns red as warning — accepted)
  • CL slider max hardcoded to 10 in UI — increase if needed
  • Per-object CL not exposed in Objects tab — only via gizmo
  • 5- and 8-toolhead machines verified in software only — not yet exercised on hardware
  • Prime-tower placeholder drawn on single-filament plates though none is generated — cosmetic; fix needs a usage-aware has_wipe_tower() (8.6.5)
  • Linux in-app update check — the AppImage requests a linux update page but the checker accepts only Windows/macOS; fix in the app first, then publish the linux pages (8.6.6)
  • Nest is greedy — a full plate can leave hand-fillable room (3 of 53 cubes in testing); next step would be a local-improvement pass or grid-snapping identical items (8.6.6)
  • Support Z distance adjustment not reached from the Unify menu / Object Table, and not re-checked on a filament material-type change (8.6.6)
  • Filament arrangement not auto-optimized — the slicer flags an unworkable map but choosing which filament goes on which nozzle (fewest changes) is still manual; automatic arrangement planned (8.6.0)
  • multiACE supply: Sidecar listed in the dropdown but not implemented (8.6.0)
  • filament_is_high_temperature stored and preserved but not acted on — chamber-cooling behavior not implemented (8.5.7-beta.2)
  • Toolhead UID identity system — each toolhead needs factory-burned UID; blocked by hardware; software architecture planned (local registry JSON, PTP stores UID arrangement)
  • Per-nozzle hardened steel toggle — allow marking individual nozzles as HS vs standard
2026年5月15日 — 开发启动
初始化
架构与代码库决策
设计目标、硬件约束、代码库选择
▾
重大决策
  • wall[0] = 0.2mm 外墙挤出口;wall[1+] = 0.4mm 内壁挤出口
  • 颜色或材料不同时最少 2 条总墙壁;否则允许 1 条
  • 仅在 wall[0] 和 wall[1] 之间进行坡度补偿间隙
  • 累加器同步:当 0.2 层累计高度超过 0.4 挤出口最大层高时触发 0.4 挤出口
  • 颜色到挤出口优先级:颜色匹配 → 最小挤出口=外墙 → 挤出机 0 兜底
  • 颜色深度:最小值=挤出口直径;薄截面=完全渗透或 50/50 分割
  • 每区域挤出口覆盖:global=YES 遵循混合逻辑;global=NO 单挤出口拥有整个区域
  • 优先级层次已锁定:CL(着色区域循环数)> OW(外墙)> IW(内壁)
  • 最初基于 OrcaSlicer-FullSpectrum 分支,后因 Filament for Features UI 更清晰改用 Snapmaker Orca
  • FullSpectrum 存在 resolved_model_config_for_tab 过滤 sparse_infill_filament 的问题,无法干净修复
  • 需要 VS2019 · CMake 3.29 · 创建脚本:build_and_run.bat · build.ps1 含计时功能
  • 系统路径中的 Strawberry Perl 会导致 CMake 版本冲突 — 修复:覆盖系统路径
  • DLL 策略:从已安装的 Snapmaker_Orca\ 复制所有文件,除了 Snapmaker_Orca.dll
  • PrintConfig.hpp 必须为 UTF-8(非 ANSI)— 第一行有 // -*- coding: utf-8 -*-;在 VS2019 编辑后需运行编码修复脚本
  • 禁止对 PrintConfig.cpp 运行编码转换 — ANSI→UTF-8 会损坏中文字符
第一阶段 — 配置方案与流水线框架(ALH=自适应层高)
第1a阶段
新文件 — NozzleLayerPlanner、ColorDepthProcessor、NozzleVerifyDialog
核心逻辑类,全部构建成功
▾
  • SyncPoint 结构体:z、accumulated_height、accumulated_layers、gap_offset、expanding、outer_wall_extruder
  • plan() 消耗 ALH 层高数据,生成同步点
  • 二分查找:sync_point_at()、outer_wall_extruder_at()、gap_offset_at()
  • apply_depth():逐层 ClipperUtils 偏移 — 已构建但尚未正确连接(见第五阶段)
  • detect_thin_sections():存根 · ThinSectionBehavior:BleedThrough | Split50_50
  • inward_offset():使用 scaled() 进行正确的 Clipper 单位转换
  • 显示工作头 T1–T4 挤出口尺寸、材料名称、颜色色块
  • 验证按钮连接至 MainFrame 打印按钮门控 · 重新切片时调用 update_extruders()
里程碑
  • 3 个文件均已注册至 CMakeLists,构建零错误
第1b–d阶段
PrintConfig 字段 + 流水线钩子 + Tab UI
新配置字段、PrintObject、PerimeterGenerator、多材料标签页
▾
  • outer_wall_loops (coInt) · outer_wall_layer_height_max (coFloat) · outer_wall_seam_position (coEnum)
  • has_mixed_nozzle_sizes (coBool) · filament_color_depth (coFloat,占位符)
  • 多材料标签页中新增"混合挤出口"选项组:outer_wall_loops、outer_wall_layer_height_max、outer_wall_seam_position
里程碑
  • 应用启动 · 多材料标签稳定 · 混合挤出口组可见 · 切片无错误
第二阶段 — 自动检测 · 2026年5月16日
第2阶段
PresetBundle 自动检测
has_mixed_nozzle_sizes 自动从 nozzle_diameter 向量计算
▾
  • 在 full_fff_config() 末尾计算 has_mixed_nozzle_sizes:任意值与 values[0] 差值 > 1e-4 → mixed=true
  • 永远不由用户设置 — 始终在配置组装时推导
  • 混合模式下 outer_wall_loops 封顶为 wall_loops(带空值检查)
里程碑
  • 混合挤出口自动检测 · 切片时 outer_wall_loops 自动封顶
第三阶段 — 代码库切换 + 挤出口验证对话框 + 打印门控 — 5月16–17日
第3a阶段
从 FullSpectrum 切换至 Snapmaker Orca 分支
更干净的基础,Filament for Features 已可用
▾
重大决策
  • FullSpectrum 存在无法解决的 resolved_model_config_for_tab 过滤问题 — sparse_infill_filament 无法在多材料标签中显示
  • Snapmaker Orca 是实际目标硬件 — 更干净的起点
  • DLL 变通方案:使用已安装的 Snapmaker_Orca DLL,除了 Snapmaker_Orca.dll → 保存至 %USERPROFILE%\SnapmakerOrcaDLLs\
第3b阶段
NozzleVerifyDialog 完整连接 + 打印门控
切片后显示对话框,打印按钮需验证后才可用
▾
  • on_slicing_completed() 中启用混合挤出口检测
  • 耗材颜色从 full_config() filament_colour 向量读取(按值存储,避免悬空指针)
  • 重新切片时调用 update_extruders() 刷新材料名称和颜色
  • get_enable_print_status():添加挤出口验证门控 · get_enable_slice_status():不添加门控
里程碑
  • 对话框显示工作头 T1–T4 挤出口尺寸、材料名称、耗材颜色 · 打印按钮需点击验证后才可用
第四阶段 — OW/IW 挤出路径分离 + UI + 逐挤出口线宽 — 5月17日 ✅(OW=外墙,IW=内壁)
第4a阶段
inner_wall_filament 字段 + UI
内壁新增挤出机选择器,下拉列表已注册
▾
  • inner_wall_filament (coInt):gui_type=i_enum_open,min=1,默认值=1 · wall_loops 标签 → "All walls" · wall_filament 标签 → "Outer wall"
  • 添加至 Filament for Features 组 · 注册至 dynamic_filament_list_1_based · 添加至 toggle_line 循环
  • fdm_process_U1.json:"inner_wall_filament":"2"
里程碑
  • 内壁下拉列表显示挤出机列表 · 默认挤出机 2
第4b–c阶段
PrintRegion 挤出路径规划 + GCode.cpp 周界分割
frExternalPerimeter → wall_filament · frPerimeter → inner_wall_filament
▾
  • extruder():frExternalPerimeter → wall_filament;frPerimeter → inner_wall_filament
  • 仅在该层存在实际 erPerimeter 实体时才添加 inner_wall_filament — 防止锥顶处产生空换料动作
  • 若为 PERIMETERS 且内外壁耗材不同且 can_sort():erExternalPerimeter → 外墙挤出机;erPerimeter → 内壁挤出机
  • 直接推入 reg.perimeters — 避免拥有临时集合(堆损坏修复)
里程碑
  • 外墙白色(挤出机 1),内壁黄色(挤出机 2) · 无崩溃
第4d–f阶段
OW>1、逐挤出口线宽、UI 润色
outer_wall_loops 驱动循环标记 · 线宽按挤出机出口直径重新缩放
▾
  • classic 路径:is_external = loop.depth < std::max(1, outer_wall_loops)
  • Arachne 路径:is_external = (int)extrusion->inset_idx < std::max(1, outer_wall_loops)
  • PrintRegion.cpp flow():比例 = config_width / nozzle[0];重新缩放 = 比例 × 实际挤出口直径
  • fdm_process_U1.json:所有线宽转换为百分比格式
  • outer_wall_loops 标签当值 > wall_loops 时变红(与橙色"已修改"状态有区别)
  • U1 挤出机出口直径:同步对话框已移除;每个挤出口独立写入 nozzle_diameter[i]
里程碑
  • 颜色色块与侧边栏匹配 · 每个挤出口可独立设置 · outer_wall_loops 标签验证正常
第五阶段 — 着色区域流水线 — 5月18–28日 ✅ 已完成
第5a阶段
着色区域 — 凸面与凹面均已正确工作 ✅
已提交 ba3d32bc68 — 涂色面单条红色循环,内核正确
▾
  • 平面(立方体):涂色面仅 1 条红线,内部白色循环+填充正确 ✅
  • 凸曲面(球体):正确 ✅
  • 凹面(环形内孔):正确单条弧线 ✅ — 修复方案:用 region slices 构建 full_model(layer.lslices 在分割时为空)
  • 相邻涂色面(同挤出口):连续红色,无白色接缝 ✅
  • MMU 工具面板中的 CL 滑块 UI ✅
  • GCode 已验证:T3 每层打印正确循环数 ✅
  • Layer.hpp:color_patch_regions(vector)— 每挤出口每层的壳带
  • PrintObjectSlice.cpp apply_mm_segmentation():shell_strip = intersection(full_model 边界带, stolen_expanded);内核归还至基础区域
  • PerimeterGenerator:loop_number 覆盖为 patch_loops-1;is_color_patch 抑制填充
  • color_patch_loops 默认值:{1,1,1,1}(适配 U1 四工作头)
第5b阶段
着色区域流水线 — 已完成 ✅
所有 CL 值、所有面类型、逐对象设置、原始模式已验证
▾
  • 原始模式:GCode 输出与原版 OrcaSlicer 完全一致 — 已通过 GCode 对比验证 ✅
  • 着色区域模式:外层 N 条循环以涂色耗材打印;内壁循环 + 填充使用基础耗材 ✅
  • 全包裹,所有 CL 值:CL=1 至 10+ 均正确 ✅
  • 局部涂色,所有 CL 值:CL=1 至 10+ 均正确,包括奇数 CL ✅
  • 混合挤出口尺寸:每个涂色挤出口使用各自的流量参数计算循环宽度 ✅
  • 逐对象 CL:打印板上每个实体可独立设置各挤出口的 CL 值 ✅
  • 填充抑制:着色区域内无填充 — 仅打印 CL 圈 ✅
  • 多涂色:T2、T3、T4 以不同 CL 涂在同一实体上均正常 ✅
  • 工程文件持久化:逐对象 CL 设置可随 3MF 正确保存/读取 ✅
  • T1(黑色)= 基础耗材,即模型区域的 wall_filament
  • T2/T3/T4 = 涂色耗材 — 用户在 T1 实体上涂色
  • color_patch_enabled[ext_idx]=false → 原始模式(直通原版流水线)
  • color_patch_enabled[ext_idx]=true 且 color_patch_loops[ext_idx]>0 → 着色区域模式
  • color_patch_loops 默认值已改为 {0,0,0,0} — 原始模式为默认行为
里程碑
第5c阶段
最终架构实现
关键文件、逐对象 CL 流程、循环宽度公式、配置传递
▾
  • color_patch_loops:GCodeConfig 中的 coInts,默认 {0,0,0,0}
  • color_patch_enabled:GCodeConfig 中的 coBools,默认 {false,false,false,false}
  • 两者均加入 posSlice 失效(Print.cpp)和 posPerimeters 失效(PrintObject.cpp)
  • 门控:if (cp_enabled && patch_loops > 0) — 两者均为真时才走 FOS 流水线
  • 逐对象读取:优先读取 model_object->config,否则回退至全局 print()->config()
  • 循环宽度 = ext_width/2 + (CL>1 ? ext_sp2 : 0) + (CL>2 ? (CL-2)×perim_sp : 0) + perim_width/2
  • 使用 target_lr(涂色挤出口的区域)获取流量参数 — 支持混合挤出口尺寸
  • shell_strip 分别存入 color_patch_regions[ext_idx] 和 color_patch_loops_effective[ext_idx]
  • mine 减法:仅减去 shell_strip(非完整 stolen)— T1 保留内部区域
  • color_patch_regions:vector — 每挤出口的壳带
  • color_patch_loops_effective:vector — 每挤出口经逐对象解析后的 CL 值
  • loop_number = patch_loops-1,在所有调整之后设置(覆盖 alternate_extra_wall 等)
  • last 覆盖为 color_patch_regions[wall_ext] 裁剪至当前面
  • 内壁偏移使用 offset_ex(非 offset2_ex)— 防止薄楔形坍塌
  • 着色区域跳过间隙检测(is_cp_region_gap)
  • 着色区域抑制填充(is_cp_region)
  • 所有 CL 圈通过 cp_loops lambda 获得 erExternalPerimeter 角色
  • 强制使用 process_classic(非 Arachne)处理着色区域
  • inner_wall_filament 已加入涂色区域配置赋值 — 原先缺失,导致内壁打印为黑色
  • cfg.wall_filament、cfg.inner_wall_filament、cfg.solid_infill_filament、cfg.sparse_infill_filament 均设置为 painted_extruder_id
  • 原始按钮(左):将 color_patch_enabled[ext_idx]=false 写入 model_object->config
  • 着色区域按钮(右):将 color_patch_enabled[ext_idx]=true 写入,并确保 color_patch_loops > 0
  • CL 滑块读写 model_object->config 中的 color_patch_loops[ext_idx]
  • on_config_change 必须传入完整预设配置 — 传局部配置无法正确传递
  • 重新切片通过 wxGetApp().plater()->update() 触发
第六阶段 — 应用重命名与品牌更新 — 5月28日 ✅
第6阶段
重命名为 FOrcaSlicer — Flexible OrcaSlicer + Fork-a-Slicer
可执行文件、DLL、安装程序、图标、Web UI、启动画面、README 全部更新 · v2.3.2-fos.1 已发布
▾
重大决策
  • version.inc:SLIC3R_APP_NAME "FOrcaSlicer" · SLIC3R_APP_KEY 必须保留 "Snapmaker_Orca" — 翻译 .mo 文件以 Snapmaker_Orca.mo 命名,更改会导致崩溃
  • src/CMakeLists.txt:OUTPUT_NAME "FOrcaSlicer"(可执行文件)· OUTPUT_NAME "FOrcaSlicer-core"(DLL)— DLL 命名为 -core 以避免 CMake 链接器与可执行文件基础名冲突
  • src/Snapmaker_Orca_app_msvc.cpp:加载 FOrcaSlicer-core.dll
  • src/slic3r/GUI/Plater.cpp + GUI_App.cpp:标题栏已更新 · 跳过启动向导(需要 Snapmaker 账号登录)
  • installer.nsi:所有引用已更新 · VIProductVersion "2.3.2.1"(Windows 资源格式仅支持整数)
  • src/FOrcaSlicer.ico:由 FOrcaSlicer_Icon.png 生成的 7 尺寸 ICO 文件
  • resources/web + images:启动画面 SVG、logo.png、Flutter Web 标题、引导页欢迎文字全部更新
  • 版本号:2.3.2-fos.1 — 基于 Snapmaker OrcaSlicer 提交 48c601c3b1(其未发布的 2.3.2 开发分支)
  • version.inc 中的版本正则仅解析 X.X.X — -fos.1 后缀在运行时被安全忽略
  • 构建:cmake --build . --config Release --target ALL_BUILD -- -m
  • 安装:cmake --build . --config Release --target INSTALL -- -m
  • 安装程序:makensis.exe /DVERSION=2.3.2-fos.1 installer.nsi
  • 便携版:Compress-Archive -Path build\FOrcaSlicer\* -DestinationPath FOrcaSlicer_Windows_Portable_V2.3.2-fos.1.zip
  • PerimeterGenerator.cpp 必须以 UTF-8(无 BOM)LF 换行保存 — 否则编码检查器以退出码 -2 报错
里程碑
  • GitHub 发布 v2.3.2 · FOrcaSlicer_Windows_Installer_V2.3.2-fos.1.exe + 便携版压缩包
第七阶段 — 着色区域顶/底面实心填充 — 5月28–30日 ✅ 已完成
第7a阶段
着色区域顶/底面实心填充 — 设计与迭代
将着色区域流水线扩展至涂色顶/底面 — 以涂色耗材打印实心填充
▾
重大决策
  • 侧壁:仅 CL 圈(shell_strip)— 现有行为不变
  • 涂色区域结束处的顶/底层:涂色挤出口获得完整 stolen 区域,按原始模式切片(自然壁圈 + 实心填充)
  • 检测方式:检查实体顶/底壳区域边界是否与涂色区域结束处重合 — 每层单次交集检查
  • 基础挤出口:顶/底层减去完整 stolen;侧壁层仅减去 shell_strip
  • discover_vertical_shells 阶梯化:若涂色挤出口 dst 在顶/底层使用完整 stolen,discover_vertical_shells 会将较大区域向下传播至壁层,产生阶梯伪影。修复:涂色挤出口 dst 始终使用 shell_strip;实心填充来自 fill_expolygons 覆盖完整暴露区域
  • fill_expolygons 裁剪:Layer.cpp 多区域路径中 fill_surfaces 被 fill_expolygons 裁剪。若 fill_expolygons 仅为 shell_strip,实心填充面会被裁掉。修复:顶/底 CP 层的 dst 包含 stolen 的暴露顶/底部分,使 fill_expolygons 覆盖完整顶面
  • 暴露区域分割:涂色区域同时跨越顶面和侧面(穿越边缘)的层,stolen 被分割 — 暴露部分获得完整 dst;侧面部分仅获得 shell_strip
  • CL 滑块触发重新切片修复:wxGetApp().plater()->update() 单独调用不会标记实体为脏数据。修复:同时调用 notify_instance_update(obj_idx, 0) + post_event(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)
  • ❌ 仅凭 top_shell_layers / bottom_shell_layers 配置检测顶/底 → 局部侧面涂色时误报
  • ❌ 跨层面积/形状一致性检查 → 速度太慢,并行循环中出现内存溢出错误
  • ❌ 从当前层向上/向下扫描 → 同样有内存溢出风险;已替换为单次边界交集检查
  • fos_near_obj_top = (layer_id >= total_layers - top_shells)
  • fos_near_obj_bottom = (layer_id < bot_shells)
  • 若接近边界:检查该边界层的 stolen 是否与实体边界相交
  • 利用上/下层的分割数据将 stolen 拆分为暴露部分与侧面部分
第7b阶段
最终状态 — 随 v2.3.2-fos.1 发布
壁层 + 顶/底层行为均正确 · 已知限制已记录
▾
  • 涂色挤出口获得 shell_strip → PerimeterGenerator 仅生成 CL 圈
  • color_patch_regions 存储 shell_strip 供 PerimeterGenerator 使用
  • 基础挤出口从 mine 中减去 shell_strip → 保留涂色区域内部
  • 涂色挤出口获得 stolen 的暴露部分作为 dst → fill_expolygons 覆盖完整顶/底面
  • color_patch_regions 不填充 → PerimeterGenerator 按原始模式运行(自然壁圈 + 实心填充)
  • color_patch_is_top_bottom 标志 → PerimeterGenerator 抑制稀疏填充,允许实心填充
  • 基础挤出口从 mine 中减去完整 segmented.expolygons → 让出完整涂色区域
  • PrintObjectSlice.cpp:着色区域流水线、顶/底检测、mine 减法、dst 赋值
  • PerimeterGenerator.cpp:CP 区域填充抑制、顶/底实心填充、top_fills 防护
  • PerimeterGenerator.hpp + Layer.hpp:新增 color_patch_is_top_bottom 指针/向量
  • LayerRegion.cpp:将 color_patch_is_top_bottom 传递至 PerimeterGenerator
  • 曲面(球体、锥体、圆柱):着色区域按原始楔形方式处理 — 回归原因未知,暂不调查;U1 主要使用场景为平面实体,优先级较低
  • UI 同步问题:偶尔需要切换"原始 → 着色区域"才能同步配置;发生频率低,变通方法简单
  • 顶/底壳边界阶梯:与原版 OrcaSlicer 多材料 discover_vertical_shells 传播行为一致 — 非回归,已接受
里程碑
第7c阶段
CL 滑块 / 模式按钮触发重新切片修复 — 5月30日 ✅
发现并修复两处根本原因 — 配置时间戳 + 失效路径
▾
  • ModelObject::config.set_key_value() 不会更新配置时间戳 → PrintApply.cpp 检测不到变化 → 返回 APPLY_STATUS_UNCHANGED → 不触发重新切片
  • color_patch_loops 和 color_patch_enabled 存储在 ModelObject::config(逐对象 DynamicConfig)中,但不是 PrintObjectConfig 的字段 → 即使时间戳更新,object_config_from_model_object 也不会将其纳入传递给 invalidate_state_by_config_options 的差异集
  • GLGizmoMmuSegmentation.cpp:在每次对 color_patch 键调用 set_key_value 后调用 mo->config.touch() — 共 5 处:原始按钮、着色区域按钮 ×2、CL 滑块、拖拽输入
  • PrintApply.cpp:当 object_config_changed 为真时,手动检查逐对象 DynamicConfig 中 color_patch_loops 或 color_patch_enabled 是否发生变化,并在调用 invalidate_state_by_config_options 前将其追加至差异集
  • PrintObject.cpp:将 color_patch 键的失效步骤从 posPerimeters 改为 posSlice — 仅周界失效在已失效时返回 false,阻止了重新切片的触发
  • GLGizmoMmuSegmentation.cpp · PrintApply.cpp · PrintObject.cpp
里程碑
  • CL 滑块与模式按钮的更改现可可靠地触发重新切片
第7d阶段
混合挤出口 + 仅外壳着色热修复 — 5月30日 ✅
三项修复随 v2.3.2-fos.1 发布
▾
  • has_mixed_nozzle_sizes 标志已定义但从未计算 — 始终为 false
  • 在 normalize_fdm_1() 中新增计算:遍历 nozzle_diameter 值,若任意值与第一个不同则将标志设为 true
  • 此修复激活了 PerimeterGenerator 中第二阶段的代码路径,使其读取混合挤出口几何结构的 outer_wall_loops
  • 着色区域 CL=1(loop_number=0)时,i0_half_width 使用 perimeter_spacing/2 — 对大挤出口(0.6/0.8mm)而言偏移量过大,内缩超出 shell_strip 宽度 → 偏移结果为空 → 着色区域缺失
  • 修复:CL=1 时使用 ext_perimeter_width/2,CL≥2 时使用 perimeter_spacing/2。条件:(is_cp_region && loop_number > 0)
  • 当所选涂色挤出口为外墙挤出口时,仅外壳着色模式无意义 — 仅会复制外墙行为
  • 防护:将 m_selected_extruder_idx 与打印配置中的 wall_filament-1 比对。若匹配:自动切换至原始模式,仅外壳着色按钮视觉禁用,提示说明原因
  • 注意:此 ImGui 版本不支持 ImGui::BeginDisabled — 改用样式颜色覆盖 + && !is_ow_extruder 条件实现
  • 新建实体上偶发的仅外壳着色配置同步问题(预先存在)— 切换"原始 → 仅外壳着色"可解决
  • 混合挤出口 + 仅外壳着色在多功能挤出口(OW/IW/填充各不同)场景下尚未完整验证 — 当前建议作为独立工作流处理
里程碑
  • 三项修复均随 v2.3.2-fos.1 发布
第八阶段 — 外部预设崩溃修复 + 混合挤出口完善 — 5月31日 ✅ · v2.3.2-fos.2 已发布
第8a阶段
外部预设崩溃修复 — 7 项问题已解决
使用 Bambu/通用预设全新安装不再崩溃 · 系统预设自动同步已禁用
▾
  • 全新安装从 Snapmaker 服务器下载 2.3.14 预设 — 与 FOrcaSlicer 2.3.2 代码库不兼容
  • 外部预设中缺少 FOrcaSlicer 专属配置选项 → UI 读取时产生空指针崩溃
  • 症状:在外部预设下点击多材料标签页时,DynamicConfig::opt_int() 发生访问违规崩溃
  • Preset.cpp Preset::normalize():在 handle_legacy_sla() 前为 outer_wall_loops、outer_wall_layer_height_max、outer_wall_seam_position、color_patch_loops、color_patch_enabled、inner_wall_filament 添加默认值
  • Tab.cpp TabPrint::reload_config():在 Tab::reload_config() 前添加相同的默认值
  • OptionsGroup.cpp get_config_value() + get_config_value2():为所有 coInt/coBool/coInts/coBools/coEnum/coEnums 分支添加空值防护 — 返回 0/false 而非崩溃
  • 症状:添加 Snapmaker U1 时,Sidebar::on_filaments_change() 在 choices.back() 处访问违规崩溃
  • 根本原因:侧边栏耗材下拉框初始化前被调用时 choices 向量为空
  • 修复:int last_selection = choices.empty() ? 0 : choices.back()->GetSelection()
  • 症状:未选择实体时点击涂色工具崩溃
  • 修复:所有 4 处 FOS 新增的 notify_instance_update 块中,对 mo_notify 添加空值检查后再访问模型对象
  • 症状:0.2mm 挤出口第二次启动时切片失败,提示"线宽过小(skin_infill_line_width)"
  • 根本原因:validate_extrusion_width 中 extrusion_width_min <= layer_height 在两者均为 0.2mm 时触发 — <= 应改为 <
  • 症状:加载 2.3.14 预设时启动崩溃,Unknown option exception: internal_solid_infill_acceleration
  • 根本原因:该选项在 GCode.cpp 和 Print.cpp 中使用但从未注册;同时存在复制粘贴错误,skeleton_infill_line_width 被赋予了错误的标签和提示文字
  • 修复:将 internal_solid_infill_acceleration 注册为独立 coFloatOrPercent 条目;恢复 skeleton_infill_line_width 的正确标签和提示文字
  • sync_system_preset 默认值从 true 改为 false — 防止全新安装时下载不兼容的 2.3.14 预设
  • 快捷方式从 "Snapmaker Orca.lnk" 重命名为 "FOrcaSlicer.lnk"
里程碑
  • 使用任意打印机预设全新安装不再崩溃 · 系统预设自动同步默认禁用
第8b阶段
混合挤出口 + 仅外壳着色完善
SLIC3R_APP_KEY 重命名 · inner_wall_filament 修复 · CL=1 大挤出口精细化
▾
  • 文件:src/common_func/common_func.hpp + version.inc
  • 应用数据现存储于 %APPDATA%\FOrcaSlicer\ 而非 %APPDATA%\Snapmaker_Orca\
  • 所有语言 .mo 文件已复制为 FOrcaSlicer.mo — 无需额外操作
  • 制作安装程序前的预备步骤:将所有语言目录中的 Snapmaker_Orca.mo 复制为 FOrcaSlicer.mo
  • 缺少 def->mode = comAdvanced 和 def->set_default_value(new ConfigOptionInt(1)) — 导致首次启动时内壁下拉框显示异常
  • 已补充两项,与 wall_filament 定义保持一致
  • 对第7d阶段修复的进一步优化:CL=1 着色区域的 i0_half_width 改用 ext_perimeter_spacing/2(而非 ext_perimeter_width/2)
  • spacing 略小于 width — 使 CL=1 单圈在所有层高下均能在 shell_strip 内正确生成,适用于大挤出口(0.6mm、0.8mm)
  • 条件:(is_cp_region && loop_number > 0) ? perimeter_spacing/2 : (is_cp_region ? ext_perimeter_spacing/2 : ext_perimeter_width/2)
  • 混用不同尺寸挤出口时仅外壳着色产生 FlowErrorNegativeSpacing(如 T1=0.2mm,T3=0.6mm)— 根本原因尚未诊断;排查方向:PrintObjectSlice.cpp shell_strip 计算 + LayerRegion.cpp 流量设置
  • 绝对首次启动时内壁下拉框可能显示异常 — 点击可刷新;根本原因是 dynamic_filament_list_1_based 在标签页控件首次创建时尚未填充
  • outer_wall_layer_height_max 字段已在 UI 中显示,但 NozzleLayerPlanner 累加器逻辑尚未实现 — 该字段目前对切片无效
第8c阶段
top_surface_line_width .3mf 读取修复 + v2.3.2-fos.2 发布
百分比线宽从 .3mf 读取时变为绝对 mm 值 · fos.2 包含第八阶段全部修复
▾
  • 症状:重新打开已保存的 .3mf 文件时,top_surface_line_width 读取为 105mm 而非 105%
  • 根本原因:线宽值序列化/反序列化至 .3mf 时百分比标志未被保留 — 以浮点数存储,% 标记丢失
  • 仅外壳着色且CL=1时,若接缝位置设为"最近"或"对齐",弧线端点处出现较大缺口 — 使用随机接缝位置可避免
  • 涂色顶/底面边界遵循原版 OrcaSlicer 壳布线逻辑 — 角分线(法线方向)分割方案计划在后续版本实现
  • 混合挤出口第二阶段(每挤出口独立周界生成器)尚未实现 — 预设中线宽仍使用绝对 mm 值
  • 绝对首次启动时内壁下拉框可能显示异常 — 点击可刷新
  • 动态调整内壁层高从而同步外墙层高尚未实现
里程碑
  • v2.3.2-fos.2 已发布 · FOrcaSlicer_Windows_Installer_V2.3.2-fos.2.exe + 便携版压缩包
第九阶段 — 挤出口面板重设计 + 混合挤出口间距 + 稳定性 — 6月3日 · v2.3.2-fos.3/fos.4
第9a阶段
混合挤出口 OW/IW 间距修复 + 流量封顶 + 稳定性
正确的外墙至内壁过渡间距 · Flow.cpp 崩溃防护 · 空值防护
▾
  • 外墙循环现使用 ext_perimeter_spacing,内壁循环使用 perimeter_spacing
  • 外墙至内壁边界的正确过渡间距:0.5 × (ext_perimeter_spacing + perimeter_spacing)
  • 仅当 wall_filament != inner_wall_filament 时激活(fos_ow_iw_split 标志)
  • with_spacing() 在宽度 < 高度时现改为封顶而非抛出异常
  • 防止仅外壳着色 + 混合挤出口在较高层高时崩溃
  • 源文件中 top_surface_line_width 修正为 "105%"(原为 "105",缺少 % 标记)
  • 注意:百分比线宽会破坏混合挤出口流量计算 — U1 打印流程预设中所有线宽保留为绝对 mm 值
  • Tab.cpp:outer_wall_loops 与 wall_loops 的颜色比较现对空配置选项添加防护
  • OptionsGroup.cpp:在 get_config_value 的 coInt 分支中添加额外空值防护
  • Tab.cpp:outer_wall_layer_height_max 选项行及切换已注释隐藏 — 待累加器同步实现后恢复
里程碑
  • v2.3.2-fos.3 随间距修复和流量封顶一同发布
第9b阶段
挤出口直径面板重设计(fos.4)
两行两列 UI · 混直径模式切换 · 自动检测 · 打印流程预设刷新链
▾
重大决策
  • 打印机预设简称 PTP · 打印流程预设简称 PRP
  • 两行两列布局取代原标签页,与耗材面板样式一致
  • 混直径模式切换开关(SwitchButton,默认关闭)— 加载 PTP 时若各挤出口直径不同则自动启用混合模式
  • 每行颜色条:0.2mm=白色,0.4mm=10%灰,0.6mm=20%灰,0.8mm=30%灰 · 标签格式:"N: X.Xmm"
  • 打印流程预设下拉框上方新增提示文字:打印流程预设按挤出口 1 直径过滤,您设置的层高决定实际切片结果
  • 更改任意挤出口 → 确认对话框(同步/取消)→ 所有挤出口同步至所选直径 → 切换至匹配系统预设 → 打印流程预设刷新
  • 各挤出口独立 — 外墙挤出口变更时更新自定义 PTP 的继承关系 → 打印流程预设刷新
  • 在各挤出口直径不同时关闭混合模式 → 确认 → 全部同步至挤出口 1 → 切换系统预设
  • update_nozzle_settings(switch_machine=true) → 从 wall_filament 读取外墙挤出口索引 → 更新 inherits → update_compatible(Always) → CallAfter → update_presets + load_current_preset
  • is_compatible_with_parent_printer() checks active_printer.preset.inherits() against compatible_printers list
  • 自定义 PTP 需要正确的 inherits:根据外墙挤出口直径设为 "Snapmaker U1 (X.X nozzle)"
  • 打印流程预设按挤出口 1 直径过滤,而非实际外墙挤出口 — 延迟至累加器层高同步实现后处理
  • 深色模式:挤出口颜色条(白/灰调)尚未测试 — 可能需要颜色反转
里程碑
  • v2.3.2-fos.4 已发布 · installer.nsi VIProductVersion 2.3.2.4
第十阶段 — 外墙挤出口 → 模型颜色同步 + 涂色擦除警告 — 6月4日 · v2.3.2-fos.5
第10a阶段
挤出口直径标题图标
新增 nozzle_diameter.svg · Plater.cpp 中接入 ScalableButton
▾
  • 新增 nozzle_diameter.svg 至 resources/images/ — 灰色顶部弧线、绿色侧线、绿色描边外椭圆、绿色填充内椭圆代表挤出口尖端
  • SVG:width="16" height="16" viewBox="0 0 16 16",内联属性,stroke-width="0.9"
  • Plater.cpp:取消注释 nozzle_icon ScalableButton,图标键更新为 "nozzle_diameter",接入 nozzle_title_sizer
第10b阶段
外墙挤出口 → 模型预览颜色同步
3D 视口和涂色工具现正确反映外墙挤出口颜色
▾
  • GL 体积颜色:vol->extruder_id → filament_colour[extruder_id-1];未涂色实体的 extruder_id 始终为 1
  • simple_render(切片后的壳体/缩略图)将 model_volume->extruder_id() 硬编码为基础颜色索引
  • 涂色工具 ebt_colors[0](未涂色面的基础颜色)同样使用 mv->extruder_id()-1
  • 重大决策:禁止设置 mo->config["extruder"] — 会通过 object_config_from_model_object 覆盖各功能耗材分配,破坏切片。颜色覆盖仅为纯视觉效果。
  • Tab.cpp on_value_change:wall_filament 变更时,通过 CallAfter 直接修补所有非修改体 GL 体积的 vol->extruder_id → update_volumes_colors_by_extruder(),不修改 mo->config
  • GLCanvas3D.cpp reload_scene:update_volumes_colors_by_extruder() 后重新读取 wall_filament,若 OW > 1 则重新应用 extruder_id 覆盖 — 确保颜色在每次 reload_scene 后持久保留
  • Tab.cpp · GLCanvas3D.cpp · Plater.cpp · resources/images/nozzle_diameter.svg
里程碑
  • v2.3.2-fos.5 已发布 · VIProductVersion 2.3.2.5
第10c阶段
外墙挤出口变更时的多材料涂色擦除警告
已实现但暂时注释 — 待测试后启用
▾
  • wall_filament 变更时:检查所有实体上 mv->is_mm_painted()
  • 若有涂色:弹出 MessageDialog — "更改外墙挤出口将擦除所有实体上的多材料涂色。"
  • 确认:对所有模型部件体积调用 mmu_segmentation_facets.reset() → plater()->update()
  • 取消:从 get_selected_preset().config 读取旧值,通过 m_config_manipulation.apply() 还原,提前返回 — 下拉框恢复原值
  • 当前已注释 — 启用前需更多测试
第十一阶段 — 外墙颜色全路径修复 + 右键旋转 + 启动修复 — 6月4日 · v2.3.2-fos.6
第11a阶段
外墙颜色覆盖 — 所有渲染路径完整修复
3DScene.cpp 核心修复 · 涂色工具基础颜色 · 缩略图渲染 · data_changed 追踪
▾
  • simple_render(壳体/缩略图)仍将 extruder_id() 硬编码为基础颜色
  • 涂色工具 ebt_colors[0] 使用 mv->extruder_id()-1,而非外墙挤出口
  • 3DScene.cpp update_colors_by_extruder:从配置读取 wall_filament,OW > 1 时对所有模型体积使用外墙挤出口索引
  • 3DScene.cpp simple_render:新增 ow_extruder 参数;idx==0 基础颜色在 OW > 1 时使用外墙挤出口
  • 3DScene.cpp render / render_with_outline:向 simple_render 传入外墙挤出口
  • GLCanvas3D.cpp render_thumbnail_internal:向 simple_render 传入外墙挤出口(拾取路径与非拾取路径均处理)
  • GLGizmoMmuSegmentation.cpp init_model_triangle_selectors:ebt_colors[0] 使用外墙挤出口颜色作为基础
  • GLGizmoMmuSegmentation.cpp update_triangle_selectors_colors + data_changed:静态变量 last_ow_ext_idx 追踪 wall_filament 变更,变更时触发颜色更新
里程碑
  • 模型颜色、缩略图和涂色工具基础颜色均正确反映外墙挤出口分配
第11b阶段
右键拖拽旋转视图 + 启动修复 + 打印流程预设保存后刷新
右键拖拽 → 旋转 · 启动时混直径模式自动检测 · 保存新打印机预设后刷新打印流程预设
▾
  • is_camera_rotate:新增 evt.RightIsDown() — 右键拖拽现与左键拖拽一样执行旋转
  • is_camera_pan:移除右键拖拽 — 平移现仅通过中键执行
  • load_current_presets 调用 update_nozzle_settings() 时未传入 switch_machine=true — 重启后混直径模式自动检测从未触发
  • 修复:update_nozzle_settings() → update_nozzle_settings(true)
  • 保存新 PTP 后,打印流程预设停留在错误的挤出口直径,直到手动重新选择 PTP
  • 修复:save_preset 中 update_presets_from_to 之后,当 m_type == TYPE_PRINTER 时调用 sidebar().update_nozzle_settings(true)
里程碑
  • v2.3.2-fos.6 已发布 · VIProductVersion 2.3.2.6
第十二阶段 — 挤出口验证面板 + 鼠标配置 + GCode 图例 — 6月5日 · v2.3.2-fos.7
第12a阶段
挤出口验证集成至 GCode 图例面板
浮动对话框替换为耗材图例内嵌面板 · 打印按钮门控保留
▾
重大决策
  • 混合挤出口切片完成后,耗材图例面板顶部(耗材列表上方)出现"挤出口验证"区域
  • 两行网格:上行显示挤出口 1–N 标签,下行显示带颜色矩形的直径值(0.2mm=白色,0.4mm=10%灰,0.6mm=20%灰,0.8mm=30%灰)
  • 绿色"验证挤出口尺寸"按钮 — 点击前打印按钮被锁定;点击后变为灰色"[OK]"状态
  • 重新切片后按钮重置为绿色"验证挤出口尺寸"
  • 浮动 NozzleVerifyDialog 已注释(保留供后续参考)
  • GCodeViewer.cpp — EViewType::ColorPrint case 中的 FOS 挤出口验证块
  • Plater.cpp — verify_nozzle_sizes()、is_nozzle_verify_required()、is_nozzle_verified()、重新切片时重置
  • MainFrame.cpp — reset_nozzle_verified()、set_nozzle_verified_only()
第12b阶段
偏好设置中的鼠标按键分配 + GCode 图例默认值
设置 → 通用:逐按键旋转/平移/不分配 · 耗材视图为默认 · 外墙在线型图例中排首位
▾
重大决策
  • 设置 → 通用("使用自由相机"下方):三行表格 — 左键拖拽 / 中键拖拽 / 右键拖拽,每行含单选按钮:旋转 | 平移 | 不分配
  • 默认值:左键=旋转,中键=平移,右键=旋转
  • 配置键:mouse_left_btn_fn、mouse_middle_btn_fn、mouse_right_btn_fn(值:"rotate" | "pan" | "none")
  • GLCanvas3D.cpp is_camera_rotate + is_camera_pan 读取新配置键
  • ColorPrint 移至 view_type_items 列表首位
  • m_view_type 默认值改为 EViewType::ColorPrint
  • sort_remove_duplicates(m_roles) 后交换 erExternalPerimeter 与 erPerimeter,使外墙显示在内壁之前
里程碑
  • v2.3.2-fos.7 已发布 · VIProductVersion 2.3.2.7
第十三阶段 — 混合挤出口逐槽耗材配置文件(FLP=耗材预设)过滤 — 6月7–8日 · v2.3.2-fos.8 / fos.8.1
第13a阶段
逐挤出口耗材配置文件过滤 — 各槽独立体积流速
挤出口 3/4(0.2mm)现自动选择 0.2mm 耗材配置 · 1.6mm³/s 而非 12mm³/s
▾
重大决策
  • PresetComboBoxes.cpp 耗材列表过滤对所有槽均使用 nozzle_diameter[0]
  • Preset.cpp update_compatible_internal 仅通过父打印机继承关系标记耗材列表兼容性 — 当打印机继承自 0.4mm 父级时,0.2mm 耗材列表被标记为不兼容
  • PresetBundle.cpp update_compatible 自动选择逻辑忽略各槽独立的挤出口直径
  • 别名冲突:"Generic PLA" 与 "Generic PLA @U1 0.2 nozzle" 共享别名 "Generic PLA" — map 键冲突导致显示/选择错误的预设
  • update_compatible_internal:FOS 块在混合挤出口打印机配置中,若 compatible_printers 匹配任意挤出口直径则标记耗材列表为兼容
  • 仅限 TYPE_FILAMENT · 使用 cp->values 的向量副本避免指针失效
  • update_compatible:在 select_other_filament_if_incompatible 门控之后添加无条件 FOS 块
  • 遍历所有耗材槽,将 compatible_printers 与各槽挤出口直径比对
  • 不匹配时:first_compatible lambda 按挤出口匹配(必要)+ 相同别名(+1000)+ 相同材料类型(+10)评分
  • PlaterPresetComboBox::update() 中逐槽显示过滤:按槽挤出口直径 + 打印机型号过滤
  • 混直径模式下 get_preset_name 返回完整预设名称
  • 为缺少挤出口后缀的预设追加 @U1 X.X nozzle — 保持命名一致性
里程碑
  • 槽 1/2(0.4mm):Generic PLA @U1 0.4 nozzle,12mm³/s ✓ · 槽 3/4(0.2mm):自动选择 Generic PLA @U1 0.2 nozzle,1.6mm³/s ✓ · v2.3.2-fos.8 已发布
第13b阶段
热修复 — FLP 下拉框锁死 + 预设重新选择时崩溃 · v2.3.2-fos.8.1
fos.8 get_preset_name 构造的虚假名称导致 0.4mm 槽下拉框卡死 · 空指针崩溃已修复
▾
  • fos.8 get_preset_name 构造了"Generic PLA @U1 0.4 nozzle"虚假名称 — 预设包中实际不存在该名称;破坏 system_presets 的 map 键匹配 → drop_down 状态卡死,ComboBox 无法重新打开。0.2mm 槽不受影响,因为"Generic PLA @U1 0.2 nozzle"是真实存在的预设名称。
  • DynamicFilamentList::update 和 DynamicFilamentList1Based::update 调用 find_preset()->get_filament_type() 时缺少空值检查 — 预设选择状态切换期间 find_preset() 返回 nullptr 导致崩溃
  • on_select_preset 中 combo->update() 在选择事件期间同步调用 — 可能导致下拉框状态损坏
  • DynamicFilamentList::update 和 DynamicFilamentList1Based::update 中添加空值防护 — 调用 get_filament_type() 前先检查 find_preset() 返回值
  • on_select_preset 中通过 wxTheApp->CallAfter 延迟执行 combo->update() — 避免选择事件处理期间损坏下拉框状态
  • 简化 get_preset_name:混直径模式下直接返回 preset.name,不再构造虚假后缀;0.4mm 基础预设原样显示(如"Generic PLA"),非 0.4mm 预设的实际名称中已含挤出口后缀
  • switch_to_tab 中添加 FOS 后缀剥离:若显示名称在预设包中找不到,通过正则表达式剥离 @U1 X.X nozzle 后缀再进行别名查找
里程碑
  • 0.4mm 槽 FLP 下拉框可正常重新打开 · 重新选择、多材料标签页、切片后均无崩溃 · fos.8 逐挤出口过滤功能保持完整 · v2.3.2-fos.8.1 已发布
第13c阶段 — 内壁耗材 + 外墙圈数保存/加载修复 — 7月12日 · v2.3.2-fos.8.2
第13c阶段
修复 — 内壁耗材 + 外墙圈数在工程保存/加载后丢失 · v2.3.2-fos.8.2
两个 FOS 键均未注册到 s_Preset_print_options · 工程重新加载时被 apply_only 过滤丢弃
▾
重大决策
  • v2.3.2-fos.8.2 定为 FOrcaSlicer 首个公开发布版本
  • 内壁耗材:已保存的分配(如 N3)重新加载后变回外墙挤出口 — 导出的 G-code 将内圈周界路由到外墙工具
  • 外墙圈数:已保存的数量在重新加载时被丢弃,静默恢复为默认值
  • 两项设置在会话内均正常生效 — 仅在关闭并重新打开工程后才暴露丢失,或从重新加载工程的 G-code 配置头中缺失这两个键可见
  • inner_wall_filament 与 outer_wall_loops 均已在 PrintConfig.cpp 中定义、在 Preset.cpp 中有 set_key_value 默认值,但都未列入 s_Preset_print_options — 即打印预设有效键的注册表
  • 工程加载时 PresetCollection::load_external_preset 通过 apply_only(combined_config, print_options) 重建配置 — 不在 print_options 中的键会被过滤;两个键在保存时写入了工程文件,但在加载时尚未到达预设即被丢弃
  • wall_filament / sparse_infill_filament / solid_infill_filament 不受影响,因为三者均已注册 — 仅两个 FOS 新增键缺失,这就是该 bug 看起来具有选择性的原因
  • 在 s_Preset_print_options 中添加 "outer_wall_loops"(位于 "wall_loops" 之后)和 "inner_wall_filament"(位于 "wall_filament" 之后)
  • installer.nsi:VIProductVersion 提升至 2.3.2.8(自 fos.7 起一直滞留在 2.3.2.7)· 未改动任何切片代码
  • 厚内部桥接:内部桥接以 nozzle_diameter × sqrt(bridge_flow) 的高度挤出,未对层高做钳制 — 混合挤出口下可能极端(0.8mm 挤出口 + 0.1mm 层高 → 单条 0.8mm 高挤出,为层高 8 倍,与下方稀疏填充重叠)。属上游 OrcaSlicer 行为而非 FOS 特有 — 原版 Orca 统一 0.8mm 挤出口 + 0.24mm 层高也出现同样现象。变通方法:当实心填充挤出口远大于层高时禁用厚内部桥接;层高感知钳制在未来版本考虑中
里程碑
  • 内壁耗材可在保存/加载后保留(保存 IW=N3 重新加载仍为 N3,G-code 将内圈周界路由到该工具)✓ · 外墙圈数可在保存/加载后保留 ✓ · 重新加载工程的 G-code 配置头现包含这两个键 ✓ · 两个字段恢复重置圆点与预设基线跟踪 ✓ · v2.3.2-fos.8.2 已发布
第13d阶段 — 厂商配置文件刷新 + 重复配置清理 — 7月13日 · v2.3.2-fos.8.3
第13d阶段
修复 — 修正后的 Snapmaker 配置文件从未送达已安装机器 · v2.3.2-fos.8.3
预设包版本号滞留导致缓存配置冻结在损坏的 105% 状态 · 20 个重名配置文件 · About 对话框 FOrcaSlicer 品牌化
▾
  • 同一工程文件在两台电脑上产生不同的线宽 — 升级安装的机器在质量标签页中显示百分比与毫米混杂,其中顶面线宽为裸"105"(无 % 号,即 105 毫米)
  • 仅 0.4mm 挤出口预设受影响;0.2/0.6/0.8 正常 · 全新安装也正常 — 这正是问题难以定位的原因
  • 并非表面问题:线宽为 coFloatOrPercent 类型且 ratio_over = nozzle_diameter,存储的 105% 在每个挤出口上解析为不同的物理宽度(0.2 挤出口 0.21mm,0.8 挤出口 0.84mm)— 混合挤出口下会静默改变实际打印结果
  • U1 打印预设经历三次修订:df0a7e9d58(毫米 → 105%/110%,顶面线宽变成裸 105)、03a404bda3(修复 105 → 105%)、7b5c73e1af(全部改回绝对毫米值)— 修正后的毫米值此后一直随 resources/profiles/ 打包发布
  • PresetUpdater::check_installed_vendor_profiles 仅在资源包声明更新版本时才刷新 %APPDATA%/FOrcaSlicer/system/<Vendor>/ — Snapmaker.json 在历次 FOS 配置修改中始终停留在"02.02.46.02",检查从未触发,机器一直保留最初安装的配置(冻结在 df0a7e9d58 状态)
  • 每次配置修复都被如实打入安装包,然后在升级时被静默忽略
  • 20 个打印配置文件与真实同级文件声明了相同的"name"键 → 预设绑定不确定:19 个"* copy.json"文件(0.2/0.6/0.8 预设)+ "0.20 Standard @Snapmaker U1 (0.4 nozzle)_old.json"
  • _old.json 正是 0.4 挤出口的重名冲突 — 这就是 0.4 出问题的原因;它是更早更瘦的旧修订版,且未被 Snapmaker.json 索引引用(此前的清理提交 eeebb38a47 / 710caf2ac1 仅在开发分支,从未发布)
  • Snapmaker.json 预设包版本 02.02.46.02 → 02.02.47.00 — Semver::parse 仅解析 3 段版本号(第 4 段对比较不可见),将 .02 改为 .03 毫无作用;提升补丁段(46 → 47)才使 2.2.46 < 2.2.47 成立并触发刷新 · 同时使 FOS 版本号领先于 Snapmaker 官方的 02.02.46.x,官方在线更新器不会将其覆盖
  • 删除上述 20 个重名配置文件 — install_bundles_rsrc 在重新复制前对厂商文件夹调用 remove_all(),因此版本提升既送达修正配置,也将陈旧文件从已安装机器上清除
  • libslic3r.h SLIC3R_APP_FULL_NAME "Snapmaker Orca" → "FOrcaSlicer" — 驱动帮助 > 关于菜单项、关于对话框标题、错误标题和 MessageDialog 标题;仅影响显示(路径由 SLIC3R_APP_KEY 驱动,已是 FOrcaSlicer)
  • common_func.hpp:新增 FOS_VERSION "2.3.2-fos.8.3" — 刻意与 Snapmaker_VERSION 分离(该宏写入 3mf 元数据、工程设置及 user_backup 文件夹名,改动会破坏工程往返并孤立现有备份)
  • AboutDialog.cpp:版本行显示"FOrcaSlicer 2.3.2-fos.8.3",下方标注"Based on Snapmaker Orca 2.3.2 / Orca Slicer" · 修复版权符号乱码 — 窄字符串字面量中的原始 U+00A9 按当前区域设置解码(GBK 代码页下渲染为汉字);现改为纯 ASCII,通过 wxString::FromUTF8 显式解码
  • 未改动任何切片代码 · 升级说明:修正配置在 8.3 首次启动时自动应用;自定义用户预设不受影响 — 仅替换 %APPDATA%\FOrcaSlicer\system\Snapmaker\ 下的系统预设包
里程碑
  • 升级至 8.3 刷新缓存的厂商预设包 — 所有 U1 线宽在每个挤出口上均以绝对毫米值加载 ✓ · 20 个重名配置从已安装机器上移除 ✓ · Snapmaker 配置树中不再有任何百分比线宽和重名 ✓ · 同一工程在不同机器上产生一致线宽 ✓ · 帮助 > 关于显示"About FOrcaSlicer",对话框显示 FOrcaSlicer 2.3.2-fos.8.3 且版权符号正确 ✓ · v2.3.2-fos.8.3 已发布
第13e阶段 — 支撑、树状支撑 + 擦料塔均按 1 号挤出口取尺寸 — 7月14日 · v2.3.2-fos.8.4
第13e阶段
修复 — 支撑、树状支撑与擦料塔的几何尺寸全部按 1 号挤出口计算 · v2.3.2-fos.8.4
单一主题:三个功能无论由哪个工具打印均按 1 号挤出口取尺寸 · 统一口径机器完全不受影响
▾
  • 在 0.2/0.4/0.6/0.8 机器上将支撑分配给 2 号耗材:切片器选对了挤出口,却让它铺 0.22mm 的线 — 那是 1 号挤出口的线宽;0.4mm 口径被要求挤出比自身还细的线条
  • 擦料塔更严重:所有工具均以 1.0mm 擦拭、2.0mm 冲料 — 包括 0.2mm 挤出口,达到自身口径的 5 倍和 10 倍
  • 这不是舍入误差 — 而是挤出口物理上无法铺出的挤出线
  • 打印预设中的绝对线宽是按 1 号挤出口(预设解析时的参考挤出口)制定的;由其他工具打印的功能必须按比例重新推导线宽。PrintRegion::flow() 一直对外墙/内壁/填充/实心填充/顶面实心填充这样做 — 但支撑角色不在该列表中,且支撑根本不经过 PrintRegion::flow():它走 Flow.cpp 中的自由函数,选对了挤出口却传入未调整的线宽
  • 树状支撑还有第二处错误:support_extrusion_width(决定树状支撑主体尺寸)从 support_interface_filament 的挤出口读取,而非主体自己的 · 另有两处硬编码 nozzle_diameter.get_at(0),将分支间距和碰撞解析直接钉死在 1 号挤出口
  • 擦料塔只保留一个标量并反复覆盖:WipeTower2::m_perimeter_width 在 set_extruder() 内赋值、每个耗材调用一次 — 最后配置的耗材因迭代顺序的偶然而胜出(0.8 × 1.25 = 1.0mm,人人如此);代码甚至明说"此后假定所有挤出机口径相同" · 而 m_filpar[idx].nozzle_diameter 一直被填充却从未被读取
  • 新增 fos_width_for_nozzle() — 1 号挤出口 → 实际打印挤出口的比例换算规则,导出后支撑、SupportParameters 与 TreeSupport 以完全一致的方式推导线宽,而非三套各自的算法;百分比线宽原样通过(get_abs_value 本就按传入挤出口取比例) · support_material_flow、support_material_1st_layer_flow、support_material_interface_flow 均改经此函数
  • SupportParameters:support_extrusion_width 改从 support_filament 读取(原为 support_interface_filament)并按比例推导 — 它决定支撑主体尺寸,此前从错误的工具取尺寸
  • TreeSupport:两处硬编码 nozzle_diameter.get_at(0) 改为支撑耗材的挤出口并按比例推导 — 二者驱动碰撞解析与分支间距;由 0.6mm 工具打印的树曾按 0.2mm 尺寸构建
  • 结构线宽(占地、边距、裙边间距、塔周界 + 稀疏填充)绑定到 wipe_tower_filament — 真正打印它们的工具(set_extruder 将其标记为唯一非水溶性耗材,first_toolchange_to_nonsoluble 因此将 finish_layer 落在其上);此前取决于哪次 set_extruder 调用最后运行
  • 擦拭与冲料现按各工具自身的线宽和流量挤出,取自 m_filpar[tool].nozzle_diameter
  • 深度规划同步跟进:plan_toolchange() 与 save_on_last_wipe() 用同一套逐工具线宽预留深度 — 线宽与间距必须同步调整,否则冲料块会过满/欠满、预留深度与实际挤出线不再吻合 · 冲料的 E 值按体积计算(ramming_speed × 时间 / 耗材截面积),仅线条长度变化,清料体积不受影响
  • 支撑/筏底、支撑/筏接触面与擦料塔提供"默认"选项 = 当前已装载的耗材打印 — 混合口径下这不是有效选择且无法修复:支撑路径在切片时以单一流量一次性生成,而工具直到 G-code 导出才确定 — ToolOrdering 在已生成的挤出线上直接改派工具,无任何重新渲染;为 0.2mm 口径构建的路径可能交给 0.8mm 口径
  • 口径不一致时:三个下拉框显示"Empty"而非"默认",且切片器拒绝切片直至选定耗材,并指明哪个下拉框为空 · 刻意不自动填充 1 号耗材 — 静默落到 1 号挤出口正是本次要修的 bug · 统一口径机器上"默认"行为与以前完全一致
  • FOS_VERSION → 2.3.2-fos.8.4 · 安装包 VIProductVersion 2.3.2.8 → 2.3.2.9 · 升级说明:使用混合口径且启用支撑/擦料塔的用户首次切片时需选定耗材;8.4 之前保存的工程打开后这些项可能为空,切片器会指明缺哪一项
  • 支撑层高仍跟随 1 号挤出口 — 与 8.x 规则(所有挤出口跟随 1 号挤出口的打印设置)一致,但 0.8mm 挤出口可能被要求打印 0.1mm 支撑层;层高钳制属新功能而非修复 — 延后
  • 冲料块与擦拭线对齐:将冲料块对齐到首条擦拭线的 Y 偏移仍使用塔的结构线宽 — 逐工具线宽下偏差可达约 0.4mm;仅外观问题,不影响清料体积和塔体几何
里程碑
  • G-code 验证(0.2/0.4/0.6/0.8,支撑主体耗材 3、接触面耗材 2、擦料塔耗材 2):支撑 0.22 → 0.66mm(0.6 工具)✓ · 接触面 0.22 → 0.44mm(0.4 工具)✓ · 塔擦拭 1.0×4 → 0.25/0.5/0.75/1.0 ✓ · 冲料 2.0×4 → 0.5/1.0/1.5/2.0 ✓ · 冲料块保持在塔壁之内 ✓ · 树状支撑分支间距随支撑挤出口缩放 ✓ · 统一口径切片完全不变(0.6×4:支撑同为 0.62mm、塔线宽同为 0.75/1.5、挤出线数量一致)✓ · v2.3.2-fos.8.4 已发布
第十四阶段 — 逐挤出口线宽与速度 — 7月14日 · v2.3.2-fos.8.5
第14阶段
逐挤出口线宽与速度 · v2.3.2-fos.8.5
每个打印特征按实际打印它的挤出口的线宽与速度打印 — 不再全部跟随 1 号挤出口 · 逐挤出口擦料塔线宽 · 层高由实际使用的最小挤出口限定
▾
  • 混合口径打印机上,每个打印特征的线宽与速度现取自实际打印它的挤出口 — 在质量和速度页的逐挤出口标签(挤出口 1–4)中设置;分配跟随打印流程耗材下拉框(外墙、内壁、填充、实心填充、支撑)
  • 线宽:外墙、内壁、顶面、稀疏填充、内部实心填充、支撑 · 速度:外墙、内壁、小周界、稀疏填充、内部实心填充、顶面、间隙填充、熨烫、支撑、支撑接触面
  • 在挤出口 2–4 标签中输入的数值立即生效 — 无需先重新加载预设
  • 每个挤出口新增擦料塔线宽字段(质量页)— 填 0 为自动(该挤出口直径 × 1.25),或手动设值;每个工具按自身线宽擦拭和冲料,塔壁与占地使用擦料塔耗材的数值
  • 此前整座塔使用最后配置的工具的单一线宽 — 0.2 挤出口可能在铺 1.0mm 的塔线
  • 层高与首层层高仍为单一全局设置,显示在挤出口标签下方 — 自动限制在实际使用的最小挤出口可打印的范围内(不能让 0.2mm 口径铺 0.6mm 的层);限制跟随分配变化,只用大口径时范围随之放宽
  • 限制也计入对象自身的耗材 — 若层高上限看起来过低,请检查对象列表中分配给对象的耗材,而不只是打印流程下拉框
里程碑
  • 已在 0.2/0.4/0.6/0.8 混合配置及 0.6 统一口径回归中通过 G-code 验证 — 统一口径打印机完全不受影响,输出与之前一致 ✓ · 尚未实机打印测试 — 欢迎反馈混合口径模型的实际打印问题 · v2.3.2-fos.8.5 已发布
第14a阶段 — 热修复:涂色区域线宽 + 1 号挤出口预设 — 7月17日 · v2.3.2-fos.8.5.1
第14a阶段
8.5 热修复 — 涂色区域应用逐挤出口线宽 + 1 号挤出口保留自身预设 · v2.3.2-fos.8.5.1
两处修复,无新功能
▾
  • 混合口径打印机上,通过涂色(色块 / 分割)分配给某挤出口的表面现按该挤出口的线宽打印 — 与通过打印流程特征下拉框分配的表面一致
  • 在 8.5 中,涂色区域无论由哪个挤出口铺设都按基础区域的线宽打印:0.2mm 口径可能被推到约 0.4mm,0.8mm 口径被压到约 0.4mm;特征下拉框分配(外墙、内壁、填充、实心填充)不受影响 — 仅涂色区域受影响。此修复恢复了 8.5 之前的行为
  • 修复后,涂色的 0.2/0.4/0.6/0.8 模型每个挤出口约铺 0.22/0.42/0.62/0.82 — 大口径上偶见较宽线条为正常的间隙填充
  • 1 号挤出口的打印流程预设现跟随 1 号挤出口自身的直径 · 此前它被绑定到打印外墙的那个挤出口:将外墙分配给其他挤出口 — 或涂色使外墙耗材非 1 号 — 会将 1 号挤出口的预设锁定到该挤出口的直径,并在重新加载时弹回
  • 1 号挤出口现无论外墙分配如何都保留自身预设;挤出口 2–4 一如既往保留各自预设
里程碑
  • 统一口径打印机完全不受影响,输出与之前一致 ✓ · 若不在混合口径机器上涂色或重新分配外墙,这些修复对你毫无影响 · v2.3.2-fos.8.5.1 已发布
第14b阶段 — 热修复:全新安装添加 U1 PTP 时崩溃 — 7月19日 · v2.3.2-fos.8.5.2
第14b阶段
8.5.1 热修复 — 全新安装时添加 Snapmaker U1 崩溃 · v2.3.2-fos.8.5.2
逐挤出口标签页中指向已扩容 std::vector 的裸指针失效 · 单一崩溃修复,无新功能
▾
  • 全新安装时添加 Snapmaker U1(混合口径 PTP)立即崩溃 — 硬性访问违例,无对话框、无错误提示
  • 逐挤出口标签页中长期存在的潜伏 bug,仅在全新安装路径上暴露;与 8.5.1 的修复无关
  • 堆栈:TabPrint::fos_reload_slot_config(Tab.cpp ~3517)→ ConfigOptionsGroup::reload_config(OptionsGroup.cpp ~750)→ get_config_value → 在 config.def() 处崩溃(~945)
  • 逐挤出口槽位的 optgroup 使用指向 m_fos_slot_configs std::vector 的裸指针构建(&m_fos_slot_configs[n])· 标签页构建与 fos_reload_slot_config 在三处调用 resize(nozzle_count) — 当 resize 使 vector 增长时会重新分配缓冲区,令所有 optgroup 的 m_config 变为悬空;下一次 reload_config() 读取已释放的 config 并崩溃
  • 全新安装时添加 U1 会使槽位 vector 增长(1 → 4)— 正是这次重新分配触发了崩溃;已有配置文件的 vector 已具备所需大小,因此不复现,故表现为"仅全新安装"
  • 已排除(记录在此以免重复排查):"contains incorrect keys: color_patch_enabled, inner_wall_filament..." 的日志刷屏是良性的 — 这些是打印流程/对象作用域的键,加载器正确地将其从机器预设中剥离,与崩溃无关 · 最初对 get_config_value 中 opt 解引用添加的空值防护是对崩溃行的误读(故障点是第 945 行的 config 访问,发生在任何 opt 解引用之前)
  • Tab.hpp:m_fos_slot_configs 由 std::vector 改为 std::deque — deque 在尾部 resize/增长时保持已有元素地址稳定,optgroup 的裸指针因此永不悬空;已确认容器无连续内存假设(仅取单元素地址,无 .data()/.reserve()/.capacity()),可直接替换,一处改动覆盖全部三个 resize 调用点
  • OptionsGroup.cpp:在 get_config_value 与 get_config_value2 中添加空值防护 — 若 config.def()->get(opt_key) 返回空则返回空值而非解引用;这是针对另一处潜伏空指针解引用的防御性加固,并非本次崩溃的修复
  • FOS_VERSION 2.3.2-fos.8.5.1 → 2.3.2-fos.8.5.2 · 安装包 VIProductVersion 2.3.2.11 → 2.3.2.12 · 8.5.1 的全部内容保持不变
  • 发布版日志在硬性崩溃时会写入中断且不含堆栈。最佳方式:在构建机上用 Visual Studio — 将 %APPDATA%\FOrcaSlicer 改名以强制全新配置,带符号在调试器下运行并复现 · WER 本地转储(HKLM LocalDumps,DumpType=2)→ 生成 .dmp,用匹配的 PDB 在 VS 中打开 · 快速定位:事件查看器 → 应用程序错误 → 故障模块 + 偏移量
里程碑
  • 已在全新配置下复现(删除 %APPDATA%\FOrcaSlicer 后添加 U1 PTP)→ 出现上述堆栈的硬性崩溃;应用 deque 修复并重新构建后,同一路径 → 不再崩溃,已由用户确认 ✓ · v2.3.2-fos.8.5.2 已发布
第14c阶段 — 热修复:逐挤出口线宽在创建 PTP 时即生效 — 7月20日 · v2.3.2-fos.8.5.3
第14c阶段
8.5.2 热修复 — 逐挤出口线宽在创建混合口径 PTP 时即刻生效 · v2.3.2-fos.8.5.3
optgroup 惰性构建导致首次切片在打开质量页前对所有挤出口都用 1 号线宽 · 单一修复,无新功能
▾
  • 混合口径打印机上,创建新的打印类型配置(PTP)时已为每个挤出口分配了正确的打印流程预设,但切片仍对所有挤出口使用 1 号挤出口的线宽,直到你打开质量页(或重新选择某挤出口的打印流程预设)
  • 涂色区域表现相同 — 涂色挤出口的线宽在访问质量页前不生效;这解释了跨机器差异:一台安装访问过质量页,另一台没有
  • update_prp_nozzle_rows(ParamsPanel.cpp)为每个槽位自动选择正确的逐挤出口 PRP,随后调用 fos_reload_slot_config(i) 以解析 fos_nozzle_*_line_width 数组 — 但 fos_reload_slot_config 在 m_fos_slot_optgroups[slot_idx].empty() 时提前返回,而逐挤出口标签页的 optgroup 是惰性构建的,仅在首次打开质量页时才创建
  • 因此新建的 PTP 上槽位配置从未加载;fos_resolve_nozzle_arrays 使数组一直镜像自槽位 0(1 号挤出口)。打开质量页构建 optgroup 后重载才终于运行,线宽随即修正 — 探针显示 RESOLVE 卡在 ow=0.220×4(nd=0.2,0.4,0.6,0.8),打开质量页后才达到 0.220,0.420,0.620,0.820
  • 已排除:s21 的"N1 驱逐"修复并非本机制 — 探针显示 1 号挤出口 / 槽位 0 始终正确、从未被驱逐;这是不同的机制(PTP 创建时的 optgroup 时序)
  • 首次修复移除了提前返回,使加载+解析在 optgroup 为空时也运行 — 修好了创建路径,却令正常使用回归:点击某个逐挤出口标签会使所有线条塌缩为 0.2。该 bail 是承重的 — 正常使用中打印标签页会不断被销毁重建,触发单独的 fos_reload_slot_config(0),此时槽位 1..N 短暂为空;bail 阻止 fos_resolve_nozzle_arrays 在这一部分快照上运行。已完整还原
  • 教训:optgroup 为空的 bail 不只是 UI 防护 — 它保护已解析的数组不被标签页销毁/重建期间的单槽解析破坏。任何创建时的填充都必须先加载完整集合、再解析恰好一次
  • 新增 TabPrint::fos_populate_all_slots(bool mixed_active) — 从各自来源加载每个槽位配置(槽位 0 取自 *m_config;槽位 1..N-1 取自各挤出口标签存储的 selected_preset_name(),该选择在 optgroup 销毁后仍保留),随后对完整集合调用一次 fos_resolve_nozzle_arrays();不依赖 optgroup、不触发 UI 重载 · 统一模式镜像 N1 · 逐槽变更防护保留槽位手动编辑
  • ParamsPanel.cpp:在 update_prp_nozzle_rows 的逐槽自动选择循环之后调用 fos_populate_all_slots(mixed_active) — 即创建/口径变更路径 · fos_reload_slot_config 的 optgroup 为空 bail 保持不变,churn 路径仍受保护
  • FOS_VERSION 2.3.2-fos.8.5.2 → 2.3.2-fos.8.5.3 · 安装包 VIProductVersion 2.3.2.12 → 2.3.2.13 · 8.5.2/8.5.1 的全部内容保持不变
里程碑
  • G-code(cube_build_3.gcode)刀路 ;WIDTH: 按活动工具标记 — T0=0.22、T1=0.45、T2=0.62、T3 约 0.82;每个挤出口挤出自身线宽,配置块 fos_nozzle_outer_wall_line_width = 0.22,0.42,0.62,0.82 · 无需访问质量页创建即正确;点击 2 号挤出口标签不再塌缩;统一模式正确镜像 N1 ✓ · v2.3.2-fos.8.5.3 已发布
第14d阶段 — 热修复:全局特征耗材回归 + "Global" 标签 + CJK/i18n — 7月21日 · v2.3.2-fos.8.5.4
第14d阶段
8.5.3 热修复 — 全局特征对应耗材切片回归 + 单对象 "Global" 标签 + imgui CJK + zh_CN 整理 · v2.3.2-fos.8.5.4
对象被强制设为 extruder=1 覆盖了所有逐特征分配 · 四处修复,无新功能
▾
  • 对象被存储为强制 extruder=1 · PrintObject apply_to_print_region_config 第 1 步填充实质上执行:if (extruder != 0) { sparse_infill = solid_infill = wall = inner_wall = extruder; } — 因此非零的对象 extruder 会用该单一耗材覆盖所有全局逐特征分配
  • 全局设置 OW=1/IW=2/填充=3/实心=4 时,四者全部塌缩为 1 号耗材,擦拭塔消失(仅用到一种耗材)
  • 修复:保持对象 extruder = 0(未分配),从而跳过覆盖分支,特征从全局分配解析 · Model.cpp(3 处 ConfigOptionInt(1) → (0))、GUI_ObjectList.cpp(update_filament_values_for_items + 添加网格路径改回 0)· 同时恢复 OrcaSlicer 的单对象模型(对象显示颜色仅由对象级耗材决定;移除了误导性的逐特征外墙颜色预览)
  • extruder=0 此前显示为 "default",容易误解 — 它是回退/全局状态(特征回退到全局分配),并非字面意义的默认值 · 现显示为 "Global"(全局),复用已有 msgid 并与 全局/对象 模式切换保持一致
  • 六处,均带 // FOS: 标记:wxExtensions.cpp get_default_extruder_color_icon(共享图标覆盖编辑器下拉行 + 修改器/层图标)、ExtraRenderers.cpp 下拉回退行、ObjectDataViewModel.cpp 对象/修改器/层显示字符串 · 对修改器部件 / 层范围而言 0 意为"继承父级",但为同一共享图标,故均显示 "Global"
  • 乱码按钮:ImGuiWrapper::button() 仅有 wxString 重载;imgui.button(_u8L("...")) 传入 UTF-8 std::string,命中隐式 wxString(std::string) ANSI/Latin-1 构造函数 → 翻译后的 CJK 字节被错误解码 → 乱码(imgui.title 直接接受 std::string,故相邻标题显示正常)· 修复:两个按钮 _u8L → _L("验证出口尺寸"、"出口尺寸已验证")
  • 英文出口标签:出口 1..N 表头使用原始 sprintf("Nozzle %d") 未翻译 → 修复为 wxString::Format(_L("Nozzle %d")) → 出口 %d
  • 通用陷阱(已记录):任何翻译后的 _u8L 传入仅接受 wxString 的接收端都会经隐式 std::string → wxString ANSI 构造函数产生乱码 · 规则:wxString 接收端用 _L,仅 std::string/char* 接收端用 _u8L — 本轮仅审计了验证出口叠加层
  • 大范围 zh_CN 整理:耗材丝 → 耗材(137 处,含一处 耗材丝丝 重复)、default → 默认(原为 缺省)、Global → 全局、Filament for Features → 特征对应的耗材、Wipe tower → 擦拭塔、Ooze prevention → 预防渗出、新增 Preheat delta temperature → 预热温差(该 msgid 从未被提取到 .po)、移除字段标签中残留的英文 "Skirt"/"Brim"(Brim 表头 → 加固边沿);zh_TW 未改动
  • 管线根本原因(探针确认):应用加载 AddCatalog(SLIC3R_APP_KEY) = FOrcaSlicer.mo,但 gettext_po_to_mo 输出的是 Snapmaker_Orca.mo(名称错误)且调用裸 msgfmt(不在 Windows PATH 上 → 目标始终失败)— 因此运行时 zh_CN 目录冻结在手工制作的 5 月 17 日 .mo 上,.po 的修改从未到达应用
  • 修复:gettext_po_to_mo 现调用随附的 tools/msgfmt.exe 并输出 ${SLIC3R_APP_KEY}.mo = FOrcaSlicer.mo;同级 gettext_merge_po_with_pot 使用 tools/msgmerge.exe · 已验证构建 gettext_po_to_mo 目标可经官方管线从 .po 重新生成 FOrcaSlicer.mo · 所有 *.mo 已被 gitignore,目录现可从源文件复现(此前是全新构建即消失的手工产物)
里程碑
  • 全局特征对应耗材正确解析(OW=1/IW=2/填充=3/实心=4 不再塌缩,擦拭塔恢复)✓ · 单对象无耗材单元格显示 "Global"/全局 ✓ · 验证出口叠加层按钮与出口 1–4 表头正确显示中文 ✓ · zh_CN 翻译在全新构建后依然生效 ✓ · 单口径打印机不受影响 · FOS_VERSION → 2.3.2-fos.8.5.4,安装包 VIProductVersion 2.3.2.13 → 2.3.2.14 · v2.3.2-fos.8.5.4 已发布
第14e阶段 — 对象耗材以外墙为准 + 移除默认耗材回退 + PRP 缩放修复 — 7月22日 · v2.3.2-fos.8.5.5
第14e阶段
对象耗材现以其外墙为准 · 移除默认/全局回退 · 修复 PRP 面板 DPI 缩放 · v2.3.2-fos.8.5.5
对象始终携带具体耗材 — 不再有不可见的默认值
▾
  • 对象耗材现由其外墙(wall_filament)贯穿定义 — 单对象耗材列与三维对象颜色都显示外墙耗材(即打印件上实际所见),不再显示单独的对象"默认";旧的"全局"标签已移除
  • 所有入口保持同步并写入同一个值:右键菜单、内联耗材下拉框、对象表格下拉框、外墙耗材选择器、三维预览 · 以一个共享的特征组作为唯一真值源;apply_to_print_region_config 中第 1 步的对象 extruder 覆盖已删除,特征改由第 2 步复制循环解析
  • 右键"更改默认耗材" → "统一对象耗材" — 一次性将所选对象的外墙、内墙、稀疏填充与实心填充设为同一耗材(即"整个对象用耗材 N 打印"的快捷操作);对象表格下拉框执行相同操作 · 两个菜单字符串均已翻译为简体中文
  • 支撑底层/接触面与擦拭塔保留各自的耗材控件 — 混合口径打印机上它们仍必须为具体耗材(限制不变)
  • 对象列表耗材列对对象/模型零件不再提供"全局"行 — 它们列出耗材 1..N 并默认为耗材 1;参数修改器与层高范围保留继承行(对它们而言 0 = 继承仍有意义)
  • 特征耗材下拉框(外墙、内墙、稀疏填充、实心填充)仅列出耗材;若某特征仍为 0 则用耗材 1 打印 · 四个特征耗材现默认 1 / 最小 1(原为 0/0),clamp_feature_extruder 保留作为处理遗留/手改配置中 0 值的崩溃防护
  • 外墙、内墙、顶面、稀疏填充、实心填充与支撑线宽提示现说明将值设为 0 时使用默认线宽(说明既有行为,使 0 读作"继承");中文提示已更新
  • 在两台不同缩放(如 100% + 150%)显示器上,出口 2–4 的 PRP 行停留在构建时缩放而出口 1 跟随当前显示器 — 其下拉框、保存/搜索按钮与行间距显得过大。根本原因:出口 2–4 是 TabPrintNozzle 标签,会将自身从 tabs_list 移除、不在任何 msw_rescale 路径上 · 修复:新增 TabPrintNozzle::fos_rescale_row(仅缩放其拥有的下拉框/按钮/位图/行高 — 对出口标签调用完整 Tab::msw_rescale 是未定义行为)并新增 TabPrint::msw_rescale 覆盖以处理逐出口标签页槽位 optgroup;不再需要切换标签修正间距
  • 另自 8.5.4 起:修复了在较高层高下对混合口径对象切片时误报"线宽过小"并阻止切片的问题 · FOS_VERSION → 2.3.2-fos.8.5.5,安装包 VIProductVersion 2.3.2.14 → 2.3.2.15
里程碑
  • 对象身份在耗材列、三维着色、菜单、所有下拉框与预览中均以外墙为准 ✓ · 在对象/特征已携带具体耗材之处移除了默认/全局行 ✓ · PRP 行与逐出口标签页随当前显示器缩放 ✓ · 修复误报线宽过小阻止切片 ✓ · 单口径打印机不受影响 · v2.3.2-fos.8.5.5 已发布
第十五阶段 — 首个 macOS 版本 · 跨平台发布 — 7月27日 · v2.3.2-fos.8.5.6
第15阶段
首个 macOS 版本 — 通用 DMG、完成 macOS 上的重命名、统一用户数据 · v2.3.2-fos.8.5.6
切片行为无任何变化 — Windows 切片输出与 8.5.5 完全一致
▾
重大决策
  • v2.3.2-fos.8.5.6 是首个提供 macOS 版本的发布 — FOrcaSlicer 现已跨平台(Windows + macOS)
  • 提供由 GitHub Actions 从源码构建的 macOS DMG — 通用二进制(主程序、崩溃处理器与 Sentry 库均同时包含 x86_64 + arm64 切片),在 Intel 与 Apple 芯片上原生运行;最低 macOS 12.0(Monterey),已在 Intel 与 Apple 芯片(M4 Max,macOS 26)上测试
  • 未签名、未公证(无 Apple 开发者证书)— 首次启动会被拒绝并提示"Apple 无法检查其是否包含恶意软件";执行一次以清除隔离标记:xattr -dr com.apple.quarantine "/Applications/FOrcaSlicer.app",或前往 系统设置 > 隐私与安全性 > 仍要打开(Control 点按绕过方式已在 macOS 15 中移除)
  • 8.x 的重命名覆盖了 Windows 的应用名/图标/可执行文件;若干 macOS 专有代码路径不在其范围内且从未被执行(此前无 macOS 版本)。现已全部正确:应用包与可执行文件均为 FOrcaSlicer(非 "Snapmaker Orca");FOrcaSlicer 图标在各处显示,包括 Dock 图标(此前应用运行时会变回 Snapmaker 图标);语言列表恢复 — mac 构建曾以旧名生成翻译文件,导致应用找不到 FOrcaSlicer.mo 而无任何语言,现约 20 种语言均可加载
  • 若干路径仍硬编码为 Snapmaker_Orca,导致 FOrcaSlicer 同时读写自己的目录与 Snapmaker Orca 的目录;现所有路径均由应用标识键派生,FOrcaSlicer 与同时安装的任何其他 Orca 系列切片器完全独立
  • 现均从 FOrcaSlicer 自身目录读取:启动时读取的配置/网页版本文件、语言/区域检测(读取 FOrcaSlicer.conf,原为 Snapmaker_Orca.conf)、崩溃报告数据(FOrcaSlicer/SentryData)· Windows 用户:无需操作、不丢失任何设置 — 预设/配置文件一直位于 FOrcaSlicer 目录
  • 两个 GitHub Actions 工作流:通用发布构建(依赖矩阵 → 通用构建,DMG + dSYM)与单架构 x86_64 快速测试 · 修复三处各需一次失败运行才发现的 CI 缺陷:固定 CMake 3.31.6(brew 提供的 CMake 4.x 移除了 cmake_minimum_required <3.5 兼容);在任何缓存操作前卸载 Homebrew zstd(作业中途移除 zstd 会改变缓存压缩方式,导致每次查找都未命中);在检出后一次性计算依赖缓存键(已恢复的依赖前缀会改变下一次恢复的 hashFiles())· 必需步骤顺序:检出 → 移除 zstd → 计算依赖缓存键 → 缓存操作 → 其余
  • 添加 U1 PTP 后的出口标签:逐出口标签页仅显示一个标签,切换到其他页再切回即可填充其余标签 — 仅外观,预设创建正确
  • macOS 深色模式首次启动:标签页与出口直径标签可能显示为浅底浅字,切换一次系统外观即可修正 — 应用在窗口创建前采样外观且不再复检;仅外观,仅 macOS
  • macOS 版本未签名、未公证(见上方隔离说明)
里程碑
  • 通用 DMG 经验证确为通用(CI 审计:三个 Mach-O 文件均包含 x86_64 + arm64;其余全部静态链接)✓ · 在 Intel 与 Apple 芯片(M4 Max,macOS 26)上原生启动 ✓ · 全新 Mac 仅创建 ~/Library/Application Support/FOrcaSlicer/,无 Snapmaker_Orca 目录 ✓ · Windows 数据已统一,不再写入 Snapmaker_Orca ✓ · FOS_VERSION → 2.3.2-fos.8.5.6,安装包 VIProductVersion 2.3.2.15 → 2.3.2.16 · v2.3.2-fos.8.5.6 已发布,含 Windows 安装包、便携版 zip 与通用 macOS DMG
第十六阶段 — 测试版:逐出口预设突破四出口上限 — 7月29日 · v2.3.2-fos.8.5.7-beta.1
第16阶段 · 测试版
预发布 — 逐出口工艺预设不再限于四个出口 · v2.3.2-fos.8.5.7-beta.1
PRP 行与逐出口标签页现跟随打印机出口数量,无上限 · 四出口 U1 切片结果与 8.5.6 一致
▾
  • 逐出口 PRP 行,以及 质量 > 线宽 和 速度 中的逐出口标签页,此前按恰好四个槽位构建 — 出口数超过四个的打印机只得到四行,第五个及以后的槽位在切片时静默回退到出口 1 的数值
  • 现在整套界面均跟随打印机预设的出口直径列表,无上限:每个槽位都有自己的 PRP 下拉框(按该槽位出口直径过滤)并将自己的线宽与速度解析进切片;切换到出口数较少的打印机时隐藏多余行,而非残留
  • 标签条此前在页面首次绘制时固定标签数量 — 添加 U1 预设后仅显示一个标签,须切换到其他页面再切回(即 8.5.6 的已知限制),切换到出口数不同的打印机时也保留旧标签数。两者均已修复:只要出口数量变化,标签条立即重建
  • "关于"中显示 "2.3.2-fos.8.5.7-beta",不含 ".1" — 测试版序号只存在于标签和文件名中,后续测试版无需重新编译(属预期,非缺陷)
里程碑
  • 已验证:U1 四出口经软件与实机验证 · Prusa XL 五工具头与自制八工具头机型经软件验证(PRP 指定、标签页行为、G-code 中解析出的线宽/速度)· macOS(Intel)标签页修复已确认 · 四出口 U1 切片输出与 8.5.6 一致,未改动切片器代码 · v2.3.2-fos.8.5.7-beta.1(预发布)已打标签
第16a阶段 — 测试版:预设键保存修复 + 更新提醒 + 配置包 — 8月13日 · v2.3.2-fos.8.5.7-beta.2
第16a阶段 · 测试版
预发布 — 四项设置无法保存 · 更新提醒 · Snapmaker 配置包 02.02.55.02 · v2.3.2-fos.8.5.7-beta.2
切片行为与 beta.1 一致 · 不包含正在开发的耗材/出口映射
▾
  • 四个 FOS 选项已定义却从未注册到任何预设类型,因此预设下次加载时被剥离并静默恢复为默认值:色块启用 + 色块圈数(耗材)、外墙接缝位置 + 内墙最大层高(工艺)
  • 同一缺陷还在每次启动时产生数百条 "contains incorrect keys ... which were removed" 日志错误 — 每个预设一条,自带配置与保存的配置皆受影响(预设多的机器每次启动可达九百余条);程序在加载后自行插入这些键、随后又移除并归咎于文件 · 现四项均可完整往返、日志已干净 · 修复前保存的项目会以默认值加载,直到重新保存一次(与 8.2 修复一致)
  • FOS 现在会在启动时及手动触发时检查新版本 · beta 通道复选框控制是否提示预发布,"跳过此版本" 可只屏蔽某一版本而不关闭检查,下载按钮在浏览器中打开发布页(FOS 自身绝不下载或安装任何内容)· 使用 GitHub,并在受限网络下回退到自建服务器 · 仅从本版本起生效 — 8.5.6 与 beta.1 无更新检查,故此次升级需手动 · "关于"框现显示完整的 "2.3.2-fos.8.5.7-beta.2",因更新检查需精确比较该字符串
  • 从 02.02.47.00 更新而来:许多耗材在 0.4 之外新增 0.2/0.6/0.8 逐口径变体(Generic/Snapmaker ABS + ASA、Generic PC、Support For PLA、PVA、PLA Silk/Wood/CF、TPU 90A + 95A HF),新增耗材(PETG/PLA Translucent、PLA Glow/Marble/Full Spectrum),改名映射使上游改名的 U1 预设(@U1 → @U1 0.4 nozzle)延续,G-code 转义修复,并识别(存储+保留、尚未生效)filament_is_high_temperature
  • 从配置包中移除 20 个多余重名文件(19 个 "... copy.json" + 1 个 "..._old.json")— 该 _old.json 是 0.20 Standard @Snapmaker U1 (0.4 nozzle) 的陈旧副本,擦料塔参数不同且缺少质量设置 · 不会从已有安装中移除(FOS 从不删除已消失的配置)— 需手动删除 %APPDATA%\FOrcaSlicer\system\Snapmaker\process\ 中的 copy.json/_old.json,或全新安装
里程碑
  • 已验证:四个选项在保存/重新加载后完整往返 · 色块切片(三个面上色)· 配置包加载干净、启动无预设错误(撰写时 macOS 构建尚未完成)· 未改动切片器代码 · v2.3.2-fos.8.5.7-beta.2(预发布)已打标签
第十七阶段 — 8.6 正式版 · 耗材到出口映射 + 多材料供料 — 8月23日 · v2.3.2-fos.8.6.0
第17阶段
8.6 正式版 — 让混合挤出口打印如实反映自身 · v2.3.2-fos.8.6.0
任意耗材映射到任意挤出口,按实际使用的挤出口切片,组合物理上不成立时拒绝切片 · 取代两个 8.5.7 测试版
▾
重大决策
  • 主题:让混合挤出口打印如实反映自身 — 任意耗材映射到任意挤出口,按每种耗材实际使用的挤出口切片,组合在物理上无法成立时硬性拒绝切片;并新增多材料供料系统支持(首先支持 multiACE)以及一项影响所有用户的重要性能修复
  • 打破耗材只能使用同编号挤出口的旧假设(3 号耗材 → 3 号挤出口)。从挤出口面板打开映射,在接点间拖动把每种耗材接到任意挤出口 — 耗材数多于挤出口数亦可
  • 每种耗材按它自己的挤出口切片(线宽、速度、流量都跟随映射到的挤出口而非编号);下拉列表按所分配挤出口直径过滤;未分配耗材显示为未连接,接好前切片停止 · 全新启动默认为直观的一一对应映射,直到用完打印机挤出口数 · 映射保存在项目(3mf)中,而非打印机配置
  • 位于 打印机设置 > 机器 > 附件:供料系统(multiACE;Sidecar 已列出、未实现)、打印机局域网 IP:端口、模式(normal/multi/head,沿用 multiACE 术语 — 模式决定每挤出口可装载多少耗材,属切片输入,须在切片前设定)、供料单元数 / 配备单元的工具头 · "从打印机读取" 查询模式、单元数、单元驱动的工具头与已装配挤出口,完整展示、确认后才填入字段 — 绝不覆盖挤出口直径
  • "发送到 multiACE"(打印下拉菜单中)将切片文件直接上传到机器收件目录 · 导出的 G-code 始终在文件头携带机器的物理挤出口直径(fos_physical_nozzle_diameter),供料系统据此将需求与已装配硬件比对 · 映射接点标注 U#S#(单元/槽位;multi 模式下接点代表单元,head 模式下代表槽位);不再匹配的已保存分配会被保留并以红色 N/A 绘出,不被静默丢弃
  • 可将耗材标记为半透明并设 1–99 的半透明度百分比(耗材页;勾选前百分比灰显)· 用于两处纯视觉用途:耗材到挤出口映射把半透明色块绘在棋盘格背景上,切片预览可通过 实心 | 半透明 开关将其绘成透视效果(每次启动默认实心,仅在实际使用半透明耗材时出现)— 不影响切片与 G-code
  • 耗材颜色对话框新增 HEX 字段(#RRGGBB 或 RRGGBB),与拾色器/色块/HSL/RGB 双向同步;位于原禁用的"规定自定义颜色"按钮处 · Windows 标准对话框内嵌该字段;macOS 原生拾色器本已带十六进制
  • 首层线宽现跟随挤出口 — 此前是应用于所有挤出口的单一数值,在 0.2 + 0.8mm 机器上第 1 层通过两者挤出相同宽度;现每个预设自身的首层线宽用于其挤出口,边缘/裙边/支撑同样如此。即使最简单的一一映射也受影响 — 在混合机器上打印过的模型值得重新切片
  • 已使用的耗材没有挤出口时切片停止(此前静默继承 1 号挤出口直径/偏移)— 提示列出每种未分配耗材及其使用方式(绘制、按特征指定耗材、物体/零件、高度范围、支撑、擦料塔、自定义 G-code 换料)
  • 映射与硬件无法一致时切片停止:无供料系统 → 耗材必须映射到实际打印它的挤出口或口径相同的挤出口;有供料系统未声明接线 → 切片所用口径必须在某挤出口上存在;已声明接线 → 此外某口径耗材数不得超过接线一次能装载的数量(如四种耗材都按单个 0.2mm 挤出口切片但仅连两个单元,会带具体数量拒绝)· 混合机器上支撑与擦料塔耗材也须明确选择
  • 持续重绘循环已消除 — 8.5 更新线加入的两处标签条使用的控件会在自身绘制处理函数内部再次让自己失效,导致每秒 300–400 次重绘、持续不断,从打印设置页面构建起占满一个 CPU 核心直到程序关闭(使项目加载变慢、开得越久越严重)。现空闲 CPU 占用为零 · 若 8.5.6 上打开 3mf 时卡死或极慢很可能就是此因 · 同一改动还修复了这些标签条在深色模式下的显示
  • 项目导入不再与界面争抢 — 进度回调触发频率远高于显示百分比变化频率且每次更新都让出事件循环;现最多每秒更新十次
  • 包含任意出口数量的逐出口预设(beta.1),四项设置的预设键保存修复、更新提醒、Snapmaker 配置包 02.02.55.02 及移除 20 个重复文件(beta.2)
  • 保存耗材数多于挤出口数的项目会在重新打开时损坏打印机配置(4 挤出口机上 20 种耗材重开变成 20 挤出口打印机、供料设置丢失)— 现按实际配置记录打印机 · 耗材到挤出口映射不再在全新启动时为空 · 预设过滤不再假定耗材编号=挤出口编号 · 挤出口面板不再反复重建(闪烁)· 映射窗口:主题切换后刷新、LAN IP 字段宽度足以显示完整地址+端口
  • 从 beta.2 升级且已配置供料系统:请重新输入一次打印机局域网 IP — beta.2 按挤出机分别保存,升级后以拼接字符串形式沿用(127.0.0.1:7126,127.0.0.1:7126,...),看似合理但发送时报 "curl: URL using bad/illegal format";重新输入即可清除。供料系统下拉在升级后重置为"无"(预期 — 重新选择)
  • 本次发布前保存的项目携带每种耗材一个挤出口 — 用本版本重新保存一次(内嵌映射无论如何都能正确读取)· 四项设置修复前保存的项目会以默认值加载这四项,直到重新保存 · 重复配置文件不会从已有安装中移除(需手动清理或全新安装)
里程碑
  • 耗材到挤出口映射、multiACE 供料支持、半透明耗材、十六进制颜色输入、三重混合挤出口安全防护、重绘循环修复,以及两个测试版全部并入 8.6.0 · 仅 U1 经实机验证(5 与 8 工具头经软件验证)· Windows 安装包 + 便携版 zip + 通用 macOS DMG · v2.3.2-fos.8.6.0 已发布
第17a阶段 — 修订:配置文件修复(0.18 预设 + 27 个多余重复文件)— 9月1日 · v2.3.2-fos.8.6.1
第17a阶段
修订 — 随附配置文件修复,两处均在首次启动时自动修正 · v2.3.2-fos.8.6.1
8.6.0 内容不变 · 8.6.0 说明中的手动清理步骤就此作废
▾
  • 0.18 Standard @Snapmaker U1 (0.6 nozzle) 继承了正确的 0.18mm 层高却又覆盖回 0.25mm — 名为 0.18 的预设实际厚度高出 39%(改变层数、时间、强度、表面效果);同挤出口的另五个预设(0.24/0.30/0.30 Strength/0.36/0.42)均无此覆盖,说明是缺陷 · 继承自上游,Snapmaker 自己的 v2.3.5 同样存在 · 升级后该预设按 0.18mm 打印(同设置下打印更久、更细腻)
  • 27 个早已从项目删除的配置文件仍被安装包写入(19 个以 " copy.json"/"_old.json" 结尾的工艺预设、7 个改名后的耗材配置)— 打包步骤只新增/更新、从不删除,故每次构建都带下去;在全新安装与升级中都表现为重复条目 · 现打包内容完全重建并在发布前与源码树逐文件比对(10696 个文件,无缺失/多余/差异)
  • Snapmaker 配置包版本 → 02.02.55.03(正是它让已有安装在首次启动时获得上述两项修复)· macOS 构建工具可报告各阶段/总耗时、暂存目录命名统一、依赖缓存计入本地补丁 · 一个 GUI 媒体状态值改为普通整数以便在 clang 下干净编译,OpenVDB 增加 clang 16+ 补丁(均不改变行为)
里程碑
  • 无需手动操作 — 首次启动刷新随附配置目录(写入修正后的 0.18、移除 27 个多余文件),保存的用户预设不受影响 · 一处需留意:基于 0.18 派生的用户预设会保留自己存储的层高(若继承自缺陷则为 0.25mm)— 请打开确认一次 · v2.3.2-fos.8.6.1 已发布
第17b阶段 — 修订:修改挤出口直径后耗材选项消失 — 9月1日 · v2.3.2-fos.8.6.2
第17b阶段
修订 — 修改非外墙挤出口直径后耗材选项消失 · v2.3.2-fos.8.6.2
切片软件修复,非配置文件 · 不修改任何设置文件
▾
  • 混合挤出口打印机上,只有修改打印外墙的挤出口时才会重新判断哪些耗材可用;修改其他挤出口时列表仍按旧直径过滤
  • 当时看不出异常,直到下一次触发重建(打开耗材-挤出口映射窗口并点确定):该插槽下拉菜单收缩到只剩已选中的一个预设,新直径耗材无法选择、旧直径耗材已正确移除 — 两部分同时消失,看起来像"所有耗材都没了" · 影响装配多种尺寸挤出口的混合模式;保存的内容不会被修改或丢失
  • 挤出口直径处理函数只在所改为外墙挤出口时调用 update_compatible(),其他挤出口的耗材兼容性从未重算;同一逻辑还有一份重复副本在新直径写入打印机配置之前同步执行,故即便外墙挤出口也总有一条路径读到旧值 · 现刷新对每个挤出口都执行且一定在新直径写入之后,重复副本已删除 · 打印机继承哪个父配置仍只跟随外墙挤出口(决定适用哪套工艺预设 — 非逐挤出口问题)
里程碑
  • 任意挤出口的直径变化都会在数值写入后正确重新过滤耗材 ✓ · 内置配置版本与 8.6.1 相同,设置文件夹不被重写 · v2.3.2-fos.8.6.2 已发布
第17c阶段 — 挤出口面板:会话内验证、同步/独立、层高范围 + 4 处修复 + 中文补全 — 9月2日 · v2.3.2-fos.8.6.3
第17c阶段
挤出口面板新增 + 四处修复 + 补全中文翻译 · v2.3.2-fos.8.6.3
为挤出口面板和打印机设置新增三项
▾
  • 重启前不再确认 — 验证按钮下方的复选框;勾选并点验证后,重启前不再提示;切换打印机配置会清除(验证按配置区分)
  • 同步 / 独立 开关(原为"混合")— 此前是否分挤出口完全由直径推断,故四个相同直径挤出口无法分别用不同工艺预设;选"独立"即可启用,保存在打印机配置中,重启和切换打印机后仍有效
  • 层高范围随挤出口直径自动填写 — 在打印机设置中输入挤出口直径即填入该挤出口的层高上下限(仍可自行输入);缩小范围无提示,超出该直径适用范围时先询问一次
  • 同步挤出口可能覆盖您自己的打印机配置 — 切到"同步"并在未保存更改提示中选保存,会把同步后的直径写入您的配置(0.2/0.4/0.4/0.6 变成同名的四个 0.2);现在配置不被改动,软件切换到对应内置配置并先告知是哪一个
  • 同步/独立开关在保存预设后、放弃更改后、修改直径后可能显示错误状态 · 分挤出口工艺预设显示的是全局选中的预设名(含修改标记)而非各自的 — 绑定与切片正确,仅显示有误 · 层高范围在直径以非手动输入方式变化时仍保留上一个挤出口的数值
  • 中文语言包自 7 月 25 日起未重新生成,此后新增翻译从未进入软件 — 已修复 · 新增 173 条翻译(耗材-挤出口映射对话框、挤出口验证、耗材池、多材料供料页面、参数选项卡、新增提示)· nozzle 术语统一为 挤出口 · 修正 其它线宽 / 其它速度 / 外墙线数 / 预热温度差值 · 偏好设置鼠标按键行(左/中/右键拖动)已翻译
里程碑
  • 新增会话内验证、独立于直径的同步/独立、层高范围自动填写;修复四处挤出口面板/范围缺陷;中文语言包重建并补全 · v2.3.2-fos.8.6.3 已发布(Windows 安装版 + 便携版、通用 macOS DMG)
第17d阶段 — 指定由哪些挤出口打印支撑与擦塔外墙 + 分挤出口 PRP 跟随直径修复 — 9月4日 · v2.3.2-fos.8.6.4
第17d阶段
指定由哪些挤出口打印支撑和擦塔外墙 · 分挤出口工艺预设现跟随直径 · v2.3.2-fos.8.6.4
一项功能、一处修复、20 条中文翻译
▾
  • 支撑/筏层主体、支撑/筏层界面、擦塔外墙的耗材下拉列表顶部新增"自定义"选项 — 选择后启用下方对应的挤出口列表(主体/界面/擦塔外墙挤出口),每个实际挤出口占一行并标注直径;勾选允许的挤出口后输入框回显如 "1, 3 (0.4)"
  • 选择对象是挤出口而非耗材,同步和独立模式下均可用(为四个相同直径挤出口中某一个装着不愿用于支撑的耗材而设计)
  • 同一处所选挤出口必须直径相同 — 支撑在选定工具前按单一流量生成、擦塔外墙整个打印只用一个线宽;勾选一个后其余不同直径挤出口变灰,选择不满足时切片被拒绝(指明涉及的挤出口)· 您的选择优先于换料效率:被选中的挤出口每层(含首层)都使用,为擦塔外墙选定但盘面别处未用的挤出口仍会打印擦塔
  • "擦拭塔"更名为"擦塔外墙"(该设置一直只控制外墙);相关两条切片提示同步调整
  • 启用"独立"后,修改某挤出口直径只更新其耗材列表,该挤出口的工艺预设仍停留在旧直径直到保存打印机预设(1 号改成 0.6 后耗材按 0.6 过滤,而工艺预设仍是 0.4)· 现包括 1 号在内每个挤出口在直径变化时立即重新选取匹配的工艺预设,此前保存的单挤出口选择不再覆盖当前直径 · 独立模式下 1 号挤出口行上方新增说明:目前只有 1 号挤出口的工艺预设会影响层高
  • 新增 20 条:三个挤出口选择控件及提示、各下拉列表的"自定义"行、下拉列表中的挤出口行,以及拒绝无效选择的六条切片提示 · 术语沿用语言包 — 挤出口、自定义、擦塔外墙、支撑/筏层主体、支撑/筏层界面 · 其他语言回退英文
里程碑
  • 分挤出口的支撑/擦塔外墙挤出口选择已发布(直径一致、同步或独立、每层生效);分挤出口工艺预设现对每个挤出口跟随当前直径 · v2.3.2-fos.8.6.4 已发布(Windows 安装版 + 便携版、通用 macOS DMG)
第17e阶段 — 修订:对象耗材身份(7 处修复)+ 着色区域崩溃 + 误要求擦塔外墙挤出口 — 9月10日 · v2.3.2-fos.8.6.5
第17e阶段
修订 — 对象耗材的设置与显示、一处崩溃、三种误要求擦拭塔的情况 · v2.3.2-fos.8.6.5
不新增功能 · 由一个问题报告追出的一组缺陷
▾
  • 一个报告 — 把立方体统一为 4 号耗材后打开涂色工具,立方体显示为 1 号 — 只是一组缺陷的可见症状:对象身份在 7月22日 改为由对象自身的外墙设置决定后,设置对象耗材的四个控件彼此不一致
  • 涂色工具只读取全局设置中的外墙耗材;现按 零件 → 对象 → 全局 的顺序解析,与其他各处一致,涂色工具、3D 视图和多材料标签页显示相同
  • 对象列表 Fila. 列的下拉框只修改外墙,内壁、稀疏填充和实心填充仍停留在原耗材(外皮一种颜色、内部另一种)— 现设置整组耗材,与"统一此物体耗材"和对象/零件设置表一致
  • 在该下拉框中选择后,需按回车、点击别处或转动视图才生效 · 多材料标签页的"特征对应的耗材"各行显示旧耗材,直到重新选中对象
  • 切片可能在着色区域处理中崩溃,是否触发取决于着色层落在对象的什么位置(释放后使用)— 表现为时有时无、与模型相关 · 同一处判断着色区域是否位于朝下表面的检查此前从未执行,因此着色区域底部的切片结果可能与旧版本不同(这是预期行为终于生效)
  • 用对象自身外墙耗材涂出的着色区域会使整个对象只剩一圈外墙、稀疏填充变为实心 — 着色区域与对象本体按耗材编号而非身份匹配而被混淆;现在这样的着色区域不产生任何效果,对象其他部分不受影响
  • 单一直径机器上开启"独立"会要求指定擦塔外墙挤出口 — 独立指每个挤出口拥有各自设置,不代表直径不同 · 只用一种耗材的盘面因装载了多种耗材被当作需要擦拭塔 · 未参与打印的耗材可能出现在盘面耗材列表中(擦拭塔预览中多出一种颜色)· 直径确实不同的机器仍会询问,这是正确的
  • 单耗材盘面上,准备视图仍会画出擦拭塔占位,但实际不会生成 — 仅外观问题,延后处理
里程碑
  • 四个耗材控件、涂色工具和多材料标签页对对象耗材的判断一致;着色区域崩溃及自身耗材着色缺陷已修复;只有真正打印擦拭塔时才要求指定擦塔外墙挤出口 · v2.3.2-fos.8.6.5 已发布(Windows 安装版 + 便携版、通用 macOS DMG)
第17f阶段 — Linux AppImage + 对齐到首个、首尾之间均匀分布、排样 + 支撑面 Z 距离 — 9月23日 · v2.3.2-fos.8.6.6
第17f阶段
首个 Linux 版本 · 三个多对象布局工具 · 支撑 Z 距离自动调整 · v2.3.2-fos.8.6.6
在准备视图中右键多选对象 · 新增 35 条中文翻译
▾
  • 首个 Linux 版本 — 单个自包含 AppImage,基于 Ubuntu 22.04 构建(需 glibc 2.35 及以上、FUSE 2 / libfuse2)· 极简系统首次启动前可能需要执行一次 mkdir -p ~/.config
  • 为此修复了三处构建缺陷,说明自应用改名以来从未有人成功构建过本分支的 AppImage:cmake 3.22 空参数导致配置到错误的源码目录;应用命令在两个作用域中被设为两个不同的值(打包去找一个不存在的程序,构建却报告成功);缺少 192px 图标
  • 选中两个或以上对象,右键 → 对齐到首个 → 上 / 左 / 下 / 右 — 首个选中的对象保持不动,其余对象与它的边缘对齐(俯视时"上"为盘面后方)· 不检查碰撞:同一行或同一列的对象可能重叠
  • 三个或以上对象 — 首个和最后选中的对象保持不动,中间的对象均匀分布:左 / 水平居中 / 右 / 上 / 垂直居中 / 下 使所选边缘或中心等距;水平间距和垂直间距使对象之间的空隙相等 · 两个工具都遵循在 3D 视图或对象列表中 Ctrl+单击的顺序;框选没有单击顺序,按对象列表顺序
  • 排样 → 紧密(2mm 间隙)/ 宽松(3.5mm 间隙)把选中的对象尽量紧密地排到盘面上,可移动并以 90° 为步长旋转;未选中的对象原地不动,排样绕开它们;放不下的对象移到新盘
  • 按俯视的真实轮廓而非包围盒排样,C 形或 U 形的凹口里可以放入其他对象 · 计入支撑和加固边沿 — 切片后使用上次切片的实际范围(树状支撑在底部常远超模型本身),未切片时根据模型和设置估算,并通知建议切片后再排样一次 · 无悬垂的对象不预留支撑空间
  • 对象与盘面边缘至少保持 3.5 mm,不会触发螺旋抬升边界警告 · 在几秒内尝试多种排列顺序并保留最优结果
  • 支撑面耗材与外墙耗材材料类型不同时(例如 PLA 下方用 PETG 支撑面),支撑 → 高级 中的顶部Z距离和底部Z距离会自动设为 0,并提示此前的数值 — 不同材料的支撑面只有贴合零件才能干净分离 · 同种材料的两个槽位不会触发
  • 新增 35 条:三个布局菜单及其选项、排样通知和支撑 Z 距离提示 · 术语沿用语言包 — 对齐到首个、首尾之间均匀分布、排样、紧密/宽松、加固边沿、支撑面
  • 排样逐个放置对象,不会回头重排已放置的对象 — 很满的盘面可能仍留有可手动利用的空间 · 支撑/加固边沿的预留空间只有切片后才精确
  • Linux 版暂无软件内更新检查 — AppImage 用户需自行查看发布页
  • 通过统一耗材菜单或对象表修改时不会触发 Z 距离调整,耗材材料类型改变时也不会重新检查
里程碑
  • Linux 加入 Windows 和 macOS 行列;多对象对齐到首个、首尾之间均匀分布,以及计入支撑/加固边沿的轮廓排样已发布;支撑 Z 距离跟随支撑面材料 · v2.3.2-fos.8.6.6 已发布(Windows 安装版 + 便携版、通用 macOS DMG、Linux AppImage)
待完成 / TODO
TODO
待处理事项
回归修复、代码清理、待实现功能
▾
  • 混合挤出口尺寸下仅外壳着色 FlowErrorNegativeSpacing — 尚未诊断
  • 外墙挤出口变更时的涂色擦除警告 — 已实现但注释,待测试后启用
  • 1 号挤出口的打印流程预设按设计驱动全局层高 — 现已支持分挤出口工艺预设(同步/独立,8.6.3)且 PRP 过滤已实现,但只有 1 号挤出口的 PRP 影响层高(8.6.4 已在界面注明);真正的逐挤出口层高仍待累加器同步实现
  • _u8L → wxString 乱码陷阱可能存在于任何将翻译后的 _u8L 传入仅接受 wxString 接收端之处 — 本轮仅审计了验证出口叠加层(8.5.4)
  • 修改器/层的回退图标显示 "Global",但语义为"继承父级"(共享图标)— 若需要逐类型标签则重新审视
  • 逐挤出口耗材列表完整架构延后 — 需要在 PRP 中实现逐槽速度覆盖(各挤出口的外墙/内壁/填充/顶面速度)
  • 曲面着色区域回归 — 验证球体/环形/锥体 CL 路径是否正常;如有问题,在 48c601c3b1 与当前版本之间进行二分排查
  • 仅外壳着色 CL=1 弧线端点接缝伪影(最近/对齐接缝位置)— 变通方法:使用随机接缝
  • 按实际外墙挤出口过滤打印流程预设 — 延迟至累加器层高同步实现
  • 累加器层高同步(NozzleLayerPlanner)— 尚未开始
  • 全新安装后拖拽 STL 文件失败 — 变通方法:先运行一次 OrcaSlicer 再切换;修复方向:排查 installer.nsi 的 shell 注册
  • 厚内部桥接:为桥接挤出高度添加层高感知钳制(上游 Orca 行为,混合挤出口下尤为极端 — 见 fos.8.2 已知问题)
  • 大口径挤出口的支撑层高钳制 — 支撑仍跟随 1 号挤出口的层高;0.8mm 挤出口可能被要求打印 0.1mm 支撑层(属新功能,延后 — 见 fos.8.4 已知问题)
  • 冲料块与擦拭线的 Y 对齐仍用塔结构线宽 — 逐工具线宽下偏差可达约 0.4mm;仅外观问题(见 fos.8.4 已知问题)
  • outer_wall_loops:UI 无硬性上限(标签变红作为警告 — 已接受)
  • CL 滑块最大值在 UI 中硬编码为 10 — 如有需要可调高
  • 逐对象 CL 仅可通过操作工具设置,未在对象属性面板(Objects 标签)中开放
  • 5 与 8 工具头机型仅经软件验证 — 尚未实机验证
  • 单耗材盘面上仍画出擦拭塔占位但实际不生成 — 仅外观问题;修复需让 has_wipe_tower() 感知实际用量(8.6.5)
  • Linux 软件内更新检查 — AppImage 会请求 linux 更新页,但检查逻辑只接受 Windows/macOS;需先在软件中修复,再发布 linux 更新页(8.6.6)
  • 排样为贪心算法 — 很满的盘面可能仍留有可手动填充的空间(测试中 53 个立方体有 3 个放不下);下一步可做局部优化或相同对象网格对齐(8.6.6)
  • 通过统一耗材菜单 / 对象表修改时不会触发支撑 Z 距离调整,耗材材料类型改变时也不重新检查(8.6.6)
  • 耗材排布不自动优化 — 软件会在映射不可行时提示,但为尽量减少换料而决定哪种耗材放哪个挤出口仍需手动;自动编排已规划(8.6.0)
  • multiACE 供料:下拉列表中已列出 Sidecar 但尚未实现(8.6.0)
  • filament_is_high_temperature 已存储并保留但尚未生效 — 腔体冷却行为未实现(8.5.7-beta.2)
  • 工作头 UID 身份识别系统 — 每个工作头需要出厂烧录 UID;受硬件阻塞;软件架构已规划(本地注册表 JSON,PTP 存储 UID 排列)
  • 逐挤出口钢化钢(HS)切换 — 允许单独标记各挤出口为 HS 或标准型