Merge main and resolved conflicts

This commit is contained in:
Lam Wei Lun
2026-09-09 11:05:52 +08:00
4617 changed files with 33044 additions and 16293 deletions

View File

@@ -9,6 +9,10 @@ on:
- release/* - release/*
paths: paths:
- 'resources/profiles/**' - 'resources/profiles/**'
# The extra JSON check also validates resources/printers/bambu_filament_ids.json,
# and lives in scripts/, so a PR touching only those must still run this workflow.
- 'resources/printers/**'
- 'scripts/**'
- ".github/workflows/check_profiles.yml" - ".github/workflows/check_profiles.yml"
workflow_dispatch: workflow_dispatch:
@@ -64,13 +68,14 @@ jobs:
set +e set +e
./OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -s -l 2 2>&1 | tee ${{ runner.temp }}/validate_slice.log ./OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -s -l 2 2>&1 | tee ${{ runner.temp }}/validate_slice.log
exit ${PIPESTATUS[0]} exit ${PIPESTATUS[0]}
# For now run filament subtype check only for BBL profiles until we fix other vendors' profiles. # All vendors' filament_id collisions were fixed (see scripts/filament_id_snapshot.json),
- name: validate filament subtype check for BBL profiles # so the duplicate-filament-subtype check runs tree-wide.
- name: validate filament subtype check
id: validate_filament_subtypes id: validate_filament_subtypes
continue-on-error: true continue-on-error: true
run: | run: |
set +e set +e
./OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -l 2 -v BBL -f 2>&1 | tee ${{ runner.temp }}/validate_filament_subtypes.log ./OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -l 2 -f 2>&1 | tee ${{ runner.temp }}/validate_filament_subtypes.log
exit ${PIPESTATUS[0]} exit ${PIPESTATUS[0]}
- name: validate custom presets - name: validate custom presets
@@ -217,7 +222,7 @@ jobs:
fi fi
if [ "${{ steps.validate_filament_subtypes.outcome }}" = "failure" ]; then if [ "${{ steps.validate_filament_subtypes.outcome }}" = "failure" ]; then
echo "### BBL Filament Subtype Validation Failed" echo "### Filament Subtype Validation Failed"
echo "" echo ""
echo '```' echo '```'
head -c 30000 ${{ runner.temp }}/validate_filament_subtypes.log || echo "No output captured" head -c 30000 ${{ runner.temp }}/validate_filament_subtypes.log || echo "No output captured"

1
.gitignore vendored
View File

@@ -53,3 +53,4 @@ __pycache__/
*.pyc *.pyc
*.opc *.opc
/.test/ /.test/
docs/superpowers/

View File

@@ -25,6 +25,13 @@ ctest --test-dir ./tests/libslic3r # individual suite
ctest --test-dir ./tests/fff_print ctest --test-dir ./tests/fff_print
``` ```
## Documentation
- Docs live in `docs/`; the high-level design of a subsystem goes in `docs/HLSD/<subsystem>.md`.
- Describe the design as it stands — what the subsystem does, why it exists, and the constraints that shape it. Not the route that got there: no phases, task lists, status markers, or "before/after this PR" framing.
- Planning and investigation output (brainstorms, superpowers design and plan docs) stays in `docs/superpowers/`, which is gitignored. Never commit it.
- Write a doc only when the design is not evident from the code, and when a change invalidates an existing one, update it in the same PR.
## Code Style ## Code Style
- C++17, selective C++20. PascalCase classes, snake_case functions/variables - C++17, selective C++20. PascalCase classes, snake_case functions/variables

View File

@@ -95,33 +95,6 @@ else ()
add_compile_definitions("$<$<CONFIG:Release>:WXINSPECTOR_DISABLE>") add_compile_definitions("$<$<CONFIG:Release>:WXINSPECTOR_DISABLE>")
endif () endif ()
find_package(Git)
if(DEFINED ENV{git_commit_hash} AND NOT "$ENV{git_commit_hash}" STREQUAL "")
message(STATUS "Specified git commit hash: $ENV{git_commit_hash}")
if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
# Convert the given hash to short hash
execute_process(
COMMAND ${GIT_EXECUTABLE} rev-parse --short "$ENV{git_commit_hash}"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
else()
# No .git directory (e.g., Flatpak sandbox) — truncate directly
string(SUBSTRING "$ENV{git_commit_hash}" 0 7 GIT_COMMIT_HASH)
endif()
add_definitions("-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"")
elseif(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
# Check current Git commit hash
execute_process(
COMMAND ${GIT_EXECUTABLE} log -1 --format=%h
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
add_definitions("-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"")
endif()
if(DEFINED ENV{SLIC3R_STATIC}) if(DEFINED ENV{SLIC3R_STATIC})
set(SLIC3R_STATIC_INITIAL $ENV{SLIC3R_STATIC}) set(SLIC3R_STATIC_INITIAL $ENV{SLIC3R_STATIC})
else() else()
@@ -137,6 +110,7 @@ option(SLIC3R_WARNINGS "Emit compiler warnings for OrcaSlicer sources"
option(SLIC3R_BUNDLED_WARNINGS "Emit compiler warnings for bundled third-party sources" 0) option(SLIC3R_BUNDLED_WARNINGS "Emit compiler warnings for bundled third-party sources" 0)
option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1) option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1)
option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1) option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1)
option(SLIC3R_RELATIVE_DEBUG_PATHS "Record a relative compilation directory in debug info (clang-cl)" 0)
option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0) option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0)
# Python stubgen module # Python stubgen module
@@ -379,11 +353,14 @@ if (MSVC)
add_compile_options(/Zc:lambda) add_compile_options(/Zc:lambda)
endif () endif ()
# /bigobj (Increase Number of Sections in .Obj file) # /bigobj (Increase Number of Sections in .Obj file)
add_compile_options(-bigobj)
# error C3859: virtual memory range for PCH exceeded; please recompile with a command line option of '-Zm90' or greater # error C3859: virtual memory range for PCH exceeded; please recompile with a command line option of '-Zm90' or greater
# Generate symbols at every build target, even for the release. # Generate symbols at every build target, even for the release.
# -Zm520 fixes error C3859 but forces the compiler to pre-allocate that memory for every translation unit regardless # -Zm520 fixes error C3859 but forces the compiler to pre-allocate that memory for every translation unit regardless
# combining /Zi with /FS frees up a significant amount of memory pressure across all parallel compile jobs and makes /MP faster overall. # combining /Zi with /FS frees up a significant amount of memory pressure across all parallel compile jobs and makes /MP faster overall.
add_compile_options(-bigobj /Zi /FS) if (SLIC3R_MSVC_PDB)
add_compile_options(/Zi /FS)
endif ()
# Disable STL4007: Many result_type typedefs and all argument_type, first_argument_type, and second_argument_type typedefs are deprecated in C++17. # Disable STL4007: Many result_type typedefs and all argument_type, first_argument_type, and second_argument_type typedefs are deprecated in C++17.
#FIXME Remove this line after eigen library adapts to the new C++17 adaptor rules. #FIXME Remove this line after eigen library adapts to the new C++17 adaptor rules.
add_compile_options(-D_SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING) add_compile_options(-D_SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING)
@@ -401,6 +378,16 @@ if (MSVC)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /LTCG") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /LTCG")
endif () endif ()
# Without this every object names its build directory and two worktrees never
# share cache entries. The linker still writes absolute paths into the PDB.
if (SLIC3R_RELATIVE_DEBUG_PATHS)
if (IS_CLANG_CL)
add_compile_options(-ffile-compilation-dir=.)
else ()
message(WARNING "SLIC3R_RELATIVE_DEBUG_PATHS is only implemented for clang-cl")
endif ()
endif ()
if (${CMAKE_CXX_COMPILER_ID} STREQUAL "AppleClang" AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER 15) if (${CMAKE_CXX_COMPILER_ID} STREQUAL "AppleClang" AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER 15)
add_compile_definitions(BOOST_NO_CXX98_FUNCTION_BASE _HAS_AUTO_PTR_ETC=0) add_compile_definitions(BOOST_NO_CXX98_FUNCTION_BASE _HAS_AUTO_PTR_ETC=0)
endif() endif()

View File

@@ -52,6 +52,7 @@ call :add_section "Build configuration"
call :add_arg config string "" config "release, debug, relwithdebinfo or minsizerel (default: release)" call :add_arg config string "" config "release, debug, relwithdebinfo or minsizerel (default: release)"
call :add_arg target_arch string "" arch "x64 or arm64 (default: the host architecture)" call :add_arg target_arch string "" arch "x64 or arm64 (default: the host architecture)"
call :add_arg slicer_asan bool a asan "Build the slicer with ASAN enabled" call :add_arg slicer_asan bool a asan "Build the slicer with ASAN enabled"
call :add_arg no_pch bool "" no-pch "Build without the precompiled header, implied by --cache"
call :add_section "Toolchain" call :add_section "Toolchain"
call :add_arg use_clang_cl bool l clang-cl "Use clang-cl as the compiler" call :add_arg use_clang_cl bool l clang-cl "Use clang-cl as the compiler"
@@ -60,6 +61,7 @@ call :add_arg use_ninja bool x ninja "Use the Ninja Multi-Config generator"
call :add_arg use_msbuild bool "" msbuild "Use the Visual Studio generator (default)" call :add_arg use_msbuild bool "" msbuild "Use the Visual Studio generator (default)"
call :add_arg vs_version string "" vs "Visual Studio release: 2019, 2022 or 2026 (default: autodetect)" call :add_arg vs_version string "" vs "Visual Studio release: 2019, 2022 or 2026 (default: autodetect)"
call :add_arg clang_path string "" clang-path "Path to clang-cl.exe, requires -x (default: the one from Visual Studio)" call :add_arg clang_path string "" clang-path "Path to clang-cl.exe, requires -x (default: the one from Visual Studio)"
call :add_arg cache string "" cache "Compiler cache: ccache, sccache or off, requires -l -x (default: off)"
call :add_section "How much gets rebuilt" call :add_section "How much gets rebuilt"
call :add_arg slicer_target string "" slicer-target "Build one slicer target instead of all, e.g. libslic3r" call :add_arg slicer_target string "" slicer-target "Build one slicer target instead of all, e.g. libslic3r"
@@ -391,6 +393,49 @@ if not "%clang_path%" == "" if not "%using_ninja%" == "ON" (
exit /b 1 exit /b 1
) )
set "cache_args="
if "%cache%" == "" goto :cache_ready
if /I "%cache%" == "off" goto :cache_ready
if /I "%cache%" == "ccache" goto :cache_named
if /I "%cache%" == "sccache" goto :cache_named
echo Unknown --cache value "%cache%". Expected ccache, sccache or off.
exit /b 1
REM CMake accepts a compiler launcher under any generator but only runs it
REM under Makefile and Ninja. ccache also refuses cl.exe because the build
REM passes /Zi.
:cache_named
REM Only a configure records the launcher, so --no-configure needs none.
if "%no_configure%" == "ON" goto :cache_ready
if "%build_deps%%build_slicer%" == "" goto :cache_ready
if not "%using_ninja%" == "ON" goto :cache_needs_clang
if not "%use_clang_cl%" == "ON" goto :cache_needs_clang
goto :cache_tool
:cache_needs_clang
echo --cache needs clang-cl and Ninja; add -l -x.
exit /b 1
REM Name a full path, so the recorded launcher does not depend on PATH.
:cache_tool
set "cache_exe="
for /f "tokens=*" %%i in ('where %cache% 2^>nul') do (
if not defined cache_exe set "cache_exe=%%i"
)
if not defined cache_exe (
echo %cache% is not on PATH. Install it, or leave --cache off.
exit /b 1
)
REM Forward slashes, so CMake does not read a backslash as an escape.
set "cache_exe=%cache_exe:\=/%"
set "cache_args=-DCMAKE_C_COMPILER_LAUNCHER="%cache_exe%" -DCMAKE_CXX_COMPILER_LAUNCHER="%cache_exe%""
REM Neither cache stores a compile that uses a precompiled header. sccache
REM refuses /Fp outright. ccache does too unless its sloppiness is loosened,
REM and even then most hits fall back to the slower preprocessed mode.
set "no_pch=ON"
:cache_ready
REM Ninja prints [123/456] by default, which says nothing about how far REM Ninja prints [123/456] by default, which says nothing about how far
REM along it is or how long is left. %p is a percentage, %w and %W are REM along it is or how long is left. %p is a percentage, %w and %W are
REM elapsed and remaining, but those two arrived in ninja 1.12 and an REM elapsed and remaining, but those two arrived in ninja 1.12 and an
@@ -474,6 +519,8 @@ REM real path rather than one glued onto the repository root.
for %%p in ("!build_dir!") do set "build_full=%%~fp" for %%p in ("!build_dir!") do set "build_full=%%~fp"
echo Configuration: %build_type%, %arch% echo Configuration: %build_type%, %arch%
if not "%clang_exe%" == "" echo Compiler: %clang_exe% if not "%clang_exe%" == "" echo Compiler: %clang_exe%
if "%no_pch%" == "ON" echo Precompiled header: off
if not "%cache_args%" == "" echo Compiler cache: %cache_exe%
set "SIG_FLAG=" set "SIG_FLAG="
if defined ORCA_UPDATER_SIG_KEY set "SIG_FLAG=-DORCA_UPDATER_SIG_KEY=%ORCA_UPDATER_SIG_KEY%" if defined ORCA_UPDATER_SIG_KEY set "SIG_FLAG=-DORCA_UPDATER_SIG_KEY=%ORCA_UPDATER_SIG_KEY%"
@@ -570,6 +617,10 @@ if "%build_deps%" == "ON" (
%error_check% %error_check%
) )
if not "!cache_args!" == "" (
set "deps_args=!deps_args! !cache_args!"
)
if not "%no_configure%" == "ON" ( if not "%no_configure%" == "ON" (
call :print_and_run cmake -S deps -B "!DEP_TREE!" -G "%generator%" %gen_args% -DCMAKE_BUILD_TYPE=%build_type% !deps_args! %ORCA_DEPS_CMAKE_ARGS% call :print_and_run cmake -S deps -B "!DEP_TREE!" -G "%generator%" %gen_args% -DCMAKE_BUILD_TYPE=%build_type% !deps_args! %ORCA_DEPS_CMAKE_ARGS%
%error_check% %error_check%
@@ -641,6 +692,17 @@ if "%build_slicer%" == "ON" (
set "slicer_args=!slicer_args! -DSLIC3R_ASAN=ON" set "slicer_args=!slicer_args! -DSLIC3R_ASAN=ON"
) )
REM A later -DSLIC3R_PCH=ON in ORCA_SLICER_CMAKE_ARGS still wins, because
REM CMake takes the last definition on the command line.
if "%no_pch%" == "ON" (
set "slicer_args=!slicer_args! -DSLIC3R_PCH=OFF"
)
if not "!cache_args!" == "" (
REM Relative debug paths as well, so another tree can reuse the objects.
set "slicer_args=!slicer_args! !cache_args! -DSLIC3R_RELATIVE_DEBUG_PATHS=ON"
)
REM Configuring against a tree that was never built fails deep inside REM Configuring against a tree that was never built fails deep inside
REM package resolution. Name it here instead. Skipped when -d is about to REM package resolution. Name it here instead. Skipped when -d is about to
REM build it in this same run, and under a dry run, which configures REM build it in this same run, and under a dry run, which configures
@@ -870,17 +932,18 @@ REM get_str_len <string> -> length in %ret%
echo %script_name% -s --no-configure -j 8 Rebuild quickly while iterating echo %script_name% -s --no-configure -j 8 Rebuild quickly while iterating
echo %script_name% -s --slicer-target glad Compile one target to check the toolchain echo %script_name% -s --slicer-target glad Compile one target to check the toolchain
echo %script_name% -l -x --run-tests Test that toolchain's build, not the default one echo %script_name% -l -x --run-tests Test that toolchain's build, not the default one
echo %script_name% -s -l -x --cache ccache Rebuild through a compiler cache
echo. echo.
echo Environment: echo Environment:
echo ORCA_DEPS_CMAKE_ARGS Extra arguments for the deps configure echo ORCA_DEPS_CMAKE_ARGS Extra arguments for the deps configure
echo ORCA_SLICER_CMAKE_ARGS Extra arguments for the slicer configure echo ORCA_SLICER_CMAKE_ARGS Extra arguments for the slicer configure
echo ORCA_UPDATER_SIG_KEY Update signing key baked into the slicer echo ORCA_UPDATER_SIG_KEY Update signing key baked into the slicer
echo git_commit_hash Revision to stamp, so a commit does not rebuild everything echo git_commit_hash Revision to stamp into the build, as CI does
echo NINJA_STATUS Ninja progress format, if you want your own echo NINJA_STATUS Ninja progress format, if you want your own
echo debugscript Set to ON to trace this script echo debugscript Set to ON to trace this script
echo. echo.
echo set ORCA_SLICER_CMAKE_ARGS=-DSLIC3R_PCH=OFF -DSLIC3R_MSVC_PDB=OFF echo set ORCA_SLICER_CMAKE_ARGS=-DSLIC3R_BUILD_SANDBOXES=ON -DSLIC3R_WARNINGS=OFF
echo $env:ORCA_SLICER_CMAKE_ARGS = '-DSLIC3R_PCH=OFF' (PowerShell) echo $env:ORCA_SLICER_CMAKE_ARGS = '-DSLIC3R_BUILD_SANDBOXES=ON' (PowerShell)
echo. echo.
echo --deps-args and --slicer-args cannot carry a value with spaces; use echo --deps-args and --slicer-args cannot carry a value with spaces; use
echo these instead. Neither form supports a value containing an ampersand. echo these instead. Neither form supports a value containing an ampersand.

View File

@@ -15,7 +15,13 @@ if(WIN32)
# See https://github.com/python/cpython/issues/153438 # See https://github.com/python/cpython/issues/153438
# Patch from https://github.com/python/cpython/pull/153608 # Patch from https://github.com/python/cpython/pull/153608
# This patch has not been merged to 3.12 yet so we need to apply it manually # This patch has not been merged to 3.12 yet so we need to apply it manually
set(_patch_cmd git init && ${PATCH_CMD} ${CMAKE_CURRENT_LIST_DIR}/01-windows-nuget.patch) #
# Without core.autocrlf=false the patched find_python.bat comes out LF and
# cmd.exe cannot find its goto labels.
set(_patch_cmd git init
&& ${GIT_EXECUTABLE} -c core.autocrlf=false apply --verbose
--ignore-space-change --whitespace=fix
${CMAKE_CURRENT_LIST_DIR}/01-windows-nuget.patch)
if(MSVC_VERSION EQUAL 1800) if(MSVC_VERSION EQUAL 1800)
set(_python_platform_toolset v120) set(_python_platform_toolset v120)
@@ -53,12 +59,9 @@ if(WIN32)
set(_python_pcbuild_output_dir win32) set(_python_pcbuild_output_dir win32)
endif() endif()
# pybind11 undefines _DEBUG around Python.h so a debug build links the
# release python3xx.lib; Py_DEBUG could not load release plugin modules.
set(_python_pcbuild_config Release) set(_python_pcbuild_config Release)
set(_python_layout_debug OFF)
if(DEFINED DEP_DEBUG AND DEP_DEBUG)
set(_python_pcbuild_config Debug)
set(_python_layout_debug ON)
endif()
# CPython's PCbuild needs a 64-bit-hosted toolchain: find_msbuild.bat picks the # CPython's PCbuild needs a 64-bit-hosted toolchain: find_msbuild.bat picks the
# 32-bit Bin\MSBuild.exe, whose x86 cl.exe/link.exe run out of address space # 32-bit Bin\MSBuild.exe, whose x86 cl.exe/link.exe run out of address space
@@ -101,7 +104,6 @@ if(WIN32)
-DPYTHON_BUILD_DIR=<SOURCE_DIR>/PCbuild/${_python_pcbuild_output_dir} -DPYTHON_BUILD_DIR=<SOURCE_DIR>/PCbuild/${_python_pcbuild_output_dir}
-DPYTHON_DEST_DIR=${DESTDIR}/libpython -DPYTHON_DEST_DIR=${DESTDIR}/libpython
-DPYTHON_LAYOUT_ARCH=${_python_layout_arch} -DPYTHON_LAYOUT_ARCH=${_python_layout_arch}
-DPYTHON_DEBUG=${_python_layout_debug}
-P ${CMAKE_CURRENT_LIST_DIR}/stage_windows.cmake -P ${CMAKE_CURRENT_LIST_DIR}/stage_windows.cmake
) )
elseif(APPLE) elseif(APPLE)

View File

@@ -9,9 +9,6 @@ foreach(_var PYTHON_SOURCE_DIR PYTHON_BUILD_DIR PYTHON_DEST_DIR PYTHON_LAYOUT_AR
endforeach() endforeach()
set(_python_exe "${PYTHON_BUILD_DIR}/python.exe") set(_python_exe "${PYTHON_BUILD_DIR}/python.exe")
if(PYTHON_DEBUG)
set(_python_exe "${PYTHON_BUILD_DIR}/python_d.exe")
endif()
if(NOT EXISTS "${_python_exe}") if(NOT EXISTS "${_python_exe}")
message(FATAL_ERROR "Built Python executable not found: ${_python_exe}") message(FATAL_ERROR "Built Python executable not found: ${_python_exe}")
@@ -49,22 +46,11 @@ endif()
set(_required_files set(_required_files
"${PYTHON_DEST_DIR}/Lib/encodings/__init__.py" "${PYTHON_DEST_DIR}/Lib/encodings/__init__.py"
"${PYTHON_DEST_DIR}/include/Python.h" "${PYTHON_DEST_DIR}/include/Python.h"
"${PYTHON_DEST_DIR}/python.exe"
"${PYTHON_DEST_DIR}/python${_python_abi}.dll"
"${PYTHON_DEST_DIR}/libs/python${_python_abi}.lib"
) )
if(PYTHON_DEBUG)
list(APPEND _required_files
"${PYTHON_DEST_DIR}/python_d.exe"
"${PYTHON_DEST_DIR}/python${_python_abi}_d.dll"
"${PYTHON_DEST_DIR}/libs/python${_python_abi}_d.lib"
)
else()
list(APPEND _required_files
"${PYTHON_DEST_DIR}/python.exe"
"${PYTHON_DEST_DIR}/python${_python_abi}.dll"
"${PYTHON_DEST_DIR}/libs/python${_python_abi}.lib"
)
endif()
foreach(_required_file IN LISTS _required_files) foreach(_required_file IN LISTS _required_files)
if(NOT EXISTS "${_required_file}") if(NOT EXISTS "${_required_file}")
message(FATAL_ERROR "Staged Python file missing: ${_required_file}") message(FATAL_ERROR "Staged Python file missing: ${_required_file}")

508
docs/HLSD/filament_id.md Normal file
View File

@@ -0,0 +1,508 @@
# Filament IDs (`filament_id`)
`filament_id` identifies one **filament product**: one named spool product = one id, shared by
all of that product's per-printer / per-nozzle variants, in every profile bundle that ships it.
Devices use it to match a physical spool or tray to a filament preset. It is never per-color,
per-printer, per-nozzle, or per-preset (per-preset identity is `setting_id`), and it is never
per-bundle either — PolyLite PLA carries the same id whether the preset lives in the
OrcaFilamentLibrary (OFL), Qidi, or Snapmaker bundle. The granularity is the name on the spool,
not the brand behind it: `AAA PLA Lite` and `AAA PLA Pro` are two filaments with two ids, not
variants of one.
**How it is generated:** an id is computed, never invented. `scripts/orca_id_tool.py`
mints it as a deterministic hash of the product's identity — the triple
`(filament_vendor, filament_type, filament name)`, where the filament name is the preset name
with its `@...` variant suffix stripped — producing an 8-character `OF*` code that is the
same for that product in every bundle, in every PR, on every machine. For example, Polymaker's
PolyLite PLA presets (`PolyLite PLA @base`, `PolyLite PLA@Q2-Series`, …) resolve
`filament_vendor` `Polymaker`, `filament_type` `PLA`, and filament name `PolyLite PLA`; hashing
`filament_product/Polymaker/PLA/PolyLite PLA` yields `OF5CgdDq`, and that is the id the
OrcaFilamentLibrary, OrcaArena, Qidi, and Snapmaker bundles all arrive at independently
(derivation details in the Minting section).
**How it is used:** at runtime the id is the join key between hardware and profiles.
When a printer reports what a tray holds (Bambu AMS, Qidi box, Creality CFS,
Klipper, Snapmaker), OrcaSlicer matches the reported id against the filament presets
compatible with that printer to select the right profile; other features — tray display
names, support-material detection, vitrification warnings, multi-nozzle filament grouping —
look up material properties by id alone. An id that changes is not forwarded anywhere: a
tray or record still holding the old value falls back to matching by material type until the
user re-selects the filament, so identity changes are made deliberately and rarely.
This page is the rule for authoring `filament_id` in system profiles
(`resources/profiles/**`). CI enforces everything below; the short version is:
> [!IMPORTANT]
> **Never write a `filament_id` value by hand.** A new filament gets its id from
> `python scripts/orca_id_tool.py --generate`; one already in the tree has one — inherit it.
## The design, in two pieces
Because several consumers match **globally by id alone, first hit wins** (see the next
section), any two materials sharing one id feed wrong data somewhere — a wrong tray name, a
wrong support-material flag, a wrong nozzle grouping — and inside one printer a duplicated id
makes AMS spool matching a coin toss. Hand-written ids produce such collisions constantly, so
the system is built to make them impossible:
1. **Deterministic minting.** An id is a pure hash of the product's identity — no registry to
maintain, no next-free-number ceremony, no way for two concurrent PRs to race for the same
number, and no way to get it wrong by hand, because you never write it by hand.
2. **A sanctioned snapshot.** The complete id landscape derived from the tree must equal
`scripts/filament_id_snapshot.json` exactly, so every change to ids, claims (which bundles
ship which id, and for which filament), or product identity surfaces as a reviewable diff to
one file — the maintainer gate.
## Who consumes the id
The canonical consumer is tray-to-preset matching: a device reports a tray material id
(`tray_info_idx`), and the shared matching pipeline (`PresetBundle::sync_ams_list` and
friends) resolves it to a preset. The matcher is printer-scoped and first-match-wins:
scanning only compatible root presets — system roots plus user-made custom filaments, which
are user roots carrying their own `P*` ids; a preset derived from another resolves through
its root and never matches directly — it picks the first one whose `filament_id` equals the
tray's. On a miss it falls back by filament type: a system `Generic <type>` preset
(matched by name, then by type similarity), else the slot's previous selection, else any compatible system generic or,
failing that, any compatible system preset, else the slot is skipped — every fallback
selection surfaces a user-visible notice.
Today only the Bambu AMS integration follows this pattern end to end — the device itself
reports the id, `BBLPrinterAgent` translates it out of Bambu's catalog into ours, and the
pipeline does all the matching. The other device integrations still synthesize a preset id
client-side in their agents (by type, brand, or color lookups against the loaded presets)
before the pipeline runs; they are intended to converge on the same pattern, with the
device-reported tray material id flowing through the shared matcher.
| Ecosystem | Where the tray id comes from today |
| --- | --- |
| Bambu AMS | the device itself (RFID / user tray setting), in Bambu's own `GF*` catalog; `BBLPrinterAgent` rewrites it into our id before the matcher sees it (see [The Bambu catalog map](#the-bambu-catalog-map)) |
| Qidi box | composed at runtime as `QD_<series>_<vendor>_<typeidx>` — vendor and type indices from the device's per-slot saved variables, the series digit inferred client-side from the printer model/name. No preset carries a `QD_*` value, so the slot currently resolves by filament type; mapping the composed id onto the filament's minted id belongs in the agent |
| Creality CFS | runtime brand/type scoring returns the winning preset's id |
| Klipper (AFC / Happy Hare) | runtime lookup by filament type |
| Snapmaker | runtime color/vendor/type match |
Tray-to-preset matching is printer-scoped, but **several consumers match globally by id alone,
first hit wins**: tray display names, `filament_is_support`, vitrification warnings, and
multi-nozzle filament grouping in the slicing pipeline (`FilamentGroup::try_merge_filaments`
merges plate slots sharing one `(filament_id, color)` pair, with matching
extruder-printability, onto one nozzle group; the engine is implemented but no grouping path
calls it yet).
Two *different* materials sharing one id
feed wrong data to those consumers even when the presets live in different vendors — so
cross-material id sharing is never safe. Within one printer, duplicate ids break AMS matching:
the matcher picks whichever preset loads first (it now logs an "Ambiguous AMS filament match"
warning, but the pick is still arbitrary) and the tray-edit dialog, which lists one entry per
id, hides the second preset entirely. The profile validator's `-f` check
(`check_filament_subtypes``PresetBundle::check_duplicate_filament_subtypes`) rejects this
per printer, and CI runs it tree-wide.
Two more consumer-side facts worth knowing:
- The machine-facing dialogs (AMS tray edit, AMS dry control, calibration history, extrusion
calibration) offer the filaments a connected printer can use by the same compatibility rule
the plater uses (an empty `compatible_printers` means *every* printer). Alias shadowing
still applies: a vendor's same-name profile supersedes the library generic. That is what
puts Orca Filament Library materials in those lists — deduplicated to one entry per
`filament_id` in the AMS and calibration-history dialogs, while extrusion calibration
deliberately lists every matching preset by full name.
- The id is load-bearing at startup: an instantiated system filament (one marked
`"instantiation": "true"` — see the structure rules) that resolves **no**
`filament_id` anywhere in its `inherits` chain is a hard load error in the C++ loader
(`Can not find filament_id for <name>`) that discards the entire vendor bundle (for the
OrcaFilamentLibrary itself the failure is messier: library presets loaded before the
failing one survive, and every vendor bundle whose filaments inherit from the library is
then discarded for want of a base). CI's structure check catches this before it ships.
## Do I need a new id? The one-question test
> **Would a user consider this a different spool product than anything already in the tree?**
Different polymer, different sub-brand (Basic / Matte / Silk / HF), fiber-filled sibling, or a
second selectable diameter → **new filament, new id**. The same spool tuned for another printer
or nozzle → **join the existing filament** (keep its base name and inherit it; no id
key needed). Tuning a generic material → **join the OrcaFilamentLibrary filament** (inherit
`Generic X @System` and keep the `Generic X` base name; no id key needed).
| Situation | id |
| --- | --- |
| Per-printer / per-nozzle variant of an existing material | same id (inherit it) |
| Sub-brand or product line (PLA vs PLA Matte vs PLA Silk vs PLA HF) | new id each |
| Color | never a new id |
| Second diameter of the same product (1.75 + 2.85) | sibling filament, new id |
| "High-speed" tuned for a *different printer model* | same id (it is a printer variant) |
| "High-speed" selectable *alongside* the normal preset on one printer | new name, so a new id (it is a product line) |
## Structure rules
1. **Every preset carries the id of its own product, wherever it gets it from.** The id is a
function of the preset's own triple (rule 5), and `inherits` carries settings, never
identity. So a preset may declare the key itself or inherit it from any ancestor — a
`<Filament> @base` root, a real (instantiated) preset of the same filament, an
OrcaFilamentLibrary preset — and CI checks one thing: the id it ends up with equals the
mint of *its* triple. The usual shape is one `@base` root (`"instantiation": "false"`)
declaring the key and the per-printer variants inheriting it; a filament may have several
roots — Qidi's PolyLite PLA has four per-series roots (`PolyLite PLA@Q2-Series`,
`@Q2C-Series`, `@X-Max 4-Series`, `@X-Plus 5-Series`) — which then all declare the identical
id. A branded filament that borrows a generic's settings (`Flashforge ABS Basic @FF C5`
inherits `Generic ABS @System`) declares its own id, because its triple is its own.
2. **The filament name is the base name**: the preset name with everything from the first
(optionally space-preceded) `@` stripped. `MyBrand PLA @Orca 3D Fuse1` and `MyBrand PLA@HS`
are both the filament `MyBrand PLA`.
3. **Within one filament, variants' `compatible_printers` are pairwise disjoint** — per printer,
at most one compatible instantiated preset per id, or AMS matching turns ambiguous. The
C++ validator's `-f` check enforces this, tree-wide in CI. Since one product carries one id
and cannot be split onto two, this rule is the *only* remedy for such an ambiguity: narrow
the `compatible_printers`, or retire the preset that duplicates another.
4. **Generics belong to OrcaFilamentLibrary.** A vendor tuning a generic material inherits
`Generic X @System`, keeps the `Generic X` base name (that alias is what hides the library
preset on your printers, and it is what makes its triple — and so its id — the library's)
and sets a non-empty `compatible_printers` — e.g. `Generic PLA @Sovol SV08 MAX` inherits
`Generic PLA @System` and lists three Sovol nozzles. Renaming such a preset makes it a
different product by rule 5, so it then needs its own id.
5. **Ids follow the product identity.** The id is a pure function of the product triple
`(filament_vendor, filament_type, filament name)`, so correcting any of them re-mints the id
**by design**, applied by `--generate` (preview with `--dry-run`, confine with `--vendor`) and
gated by the `--update-snapshot` diff; the exact sequence is in the FAQ. Nothing forwards
the old value, so anything outside the tree that stored it — a device tray, a calibration
record, a saved project — falls back to matching by filament type until the user re-selects
the filament. Re-mint deliberately, and only to fix a genuinely wrong identity.
(`renamed_from` still gates preset-*name* compatibility, as before.)
## Minting — nobody invents ids
New ids are deterministic, computed exactly like the `setting_id` precedent
(the `setting_id` half of `scripts/orca_id_tool.py`):
```text
FILAMENT_ID_NAMESPACE = uuid5(setting-id NAMESPACE, "filament_id")
= c4d3ff49-4c32-5534-a3e3-00894157ab97
filament_id = "OF" + base62_6( uuid5(FILAMENT_ID_NAMESPACE,
"filament_product/<filament_vendor>/<filament_type>/<filament_name>") )
```
`base62_6` is the low 6 base62 digits (alphabet `0-9A-Za-z`) of the UUID taken as a big-endian
integer, most-significant digit first; with the `OF` prefix the full id is 8 chars, within the
AMS length limit. The triple comes from the root preset's *flattened* config:
`<filament_vendor>` is the filament
**manufacturer** (`"Polymaker"`, or `"Generic"` for generics — never the printer brand),
`<filament_type>` the material type, `<filament_name>` the root's base name; the two config
values are inheritable list options and the first element counts.
Content-addressing on that triple is what makes the whole system converge. The key contains no
bundle name, so the same product mints the same id in every bundle — moving a filament into
OrcaFilamentLibrary never changes its id, and two vendors independently shipping the same
product arrive at the same id without coordinating. `Polymaker/PLA/PolyLite PLA` mints
`OF5CgdDq`, and that one id is declared by the OrcaFilamentLibrary, OrcaArena, Qidi, and
Snapmaker bundles alike; the OFL generic `Generic/PLA/Generic PLA` mints `OFDSrzZ8`, claimed
by 35 bundles — most by independent declarations converging on the same mint, the rest
purely through inheritance from the OFL preset.
Nothing but the triple feeds the mint — not the rest of the tree, not the snapshot, not what
another preset of the product happens to carry. Determined triple, determined id: one product
carries one id and there is no second acceptable value for it, so any other value on a preset
is a mismatch `--check` reports and `--generate` pulls back. Two *different* products whose
triples mint the same base62 value would be a collision (a roughly 36-bit id space against a
few thousand products); nothing salts past it: `--check` reports it naming both products,
`--generate` refuses to write it, and the remedy is a rename so their triples differ. Where
two presets of one product would be AMS-ambiguous on a printer, the fix is likewise in the
profiles — make their `compatible_printers` disjoint (structure rule 3), retire the redundant
preset, or, if they really are different products, give them different names so their triples
differ. Never a second id for one triple.
Workflow for a new filament:
```bash
# 1. Author the filament with NO filament_id key anywhere.
python scripts/orca_id_tool.py --dry-run # 2. preview the ids — writes nothing
python scripts/orca_id_tool.py --generate # 3. apply them to the profile file(s)
python scripts/orca_id_tool.py --update-snapshot # 4. record the new claims in the snapshot
python scripts/orca_id_tool.py --check # 5. validate the filament_id state
python scripts/orca_extra_profile_check.py # 6. ...and everything else CI checks
# 7. Commit the profile edits together with scripts/filament_id_snapshot.json, for review.
```
`--generate` makes every filament's id equal the mint of its own
`(filament_vendor, filament_type, filament name)` triple: it inserts one where an instantiated
filament resolves none, and re-derives one that does not match. A preset that *inherits* a
mismatching id is the one case left to the author — check 3b names it, and the fix is to inherit
a preset of the same filament or to give the preset its own key. A declaration is left alone
exactly when it already equals the one id its triple mints, and a collision (check 3d) is
reported and left unwritten. The same run assigns
`generate_preset_setting_id(vendor, type, name)` to every instantiated filament, process
and machine preset of every vendor except BBL, which keeps its authoritative `G*` ids, strips
`setting_id` from base profiles, and fixes the misspelled `settings_id` key — dropped, or, for
BBL, whose ids have no formula to fall back on, restored under the correct name. It is idempotent and
byte-preserving (indentation, BOM, and line endings intact, every edited file re-parsed to fail
loudly), and a no-op on a tree that already passes `scripts/orca_extra_profile_check.py` — the
check CI runs over both id kinds, of which `--check` is the `filament_id` half.
- `--filament-id` limits the run to `filament_id`.
- `--setting-id` limits the run to `setting_id`. The two exclude each other; pass neither to
write both.
- `--vendor VENDOR` confines the run to that bundle; repeatable. The id is a function of the
triple alone, so a narrowed run writes exactly what a full one would; `--check` reports
whatever it left outside.
- `--dry-run` reports what `--generate` would do and writes nothing; with no mode of its own it
implies `--generate`, so `--dry-run --vendor <Vendor>` previews just that bundle.
- `--profiles DIR` points the tooling at a different profile tree (default
`resources/profiles`). `--check` and `--update-snapshot` read and write the sanctioned state of
the tree they are given, so pointing them elsewhere needs `--snapshot PATH` for that tree too —
`scripts/filament_id_snapshot.json` describes `resources/profiles` and no other tree.
**Identity fixes need no separate mode.** `--generate` re-derives an id that no longer matches its
triple exactly the way it fills in a missing one, so a rename or a `filament_vendor` /
`filament_type` correction is just: fix the config, run `--generate` (confine it with `--vendor`,
preview it with `--dry-run`), then `--update-snapshot` and review the diff.
If you skip the tooling, CI fails and prints the remedy: the expected id for your filament and
the instruction to run `python scripts/orca_id_tool.py --generate`; once the id is minted, the
snapshot checks likewise point at `--update-snapshot` and tell you to commit the resulting
diff.
## Reserved namespaces — never mint or hand-write into
A **reserved namespace** is an id space no system profile may declare, because an external
catalog or a device protocol owns the values. None of them has an owning vendor: there is no
bundle — not even the one whose printers use the catalog — that may write one into a profile.
| Space | Status | Rule |
| --- | --- | --- |
| `GF*` | Bambu AMS/RFID catalog | declarable by **nobody**, BBL included: Bambu's own ids live in the generated catalog map, never in a profile |
| `QD_*` | Qidi device protocol | declarable by **nobody**, Qidi included: the box composes these ids at runtime and they are not preset ids |
| `P` + 7 hex chars (case-insensitive), `"null"` | user-created custom filaments (`CreatePresetsDialog.cpp`) | never appears in system profiles |
The two device namespaces, in detail:
- **Bambu (`GF*`).** Bambu's device/RFID/cloud catalog is external and opaque, which is a
reason to keep it out of the profiles rather than to let one bundle own it. Every BBL filament
mints an `OF` id from its triple like every other vendor's, and the correspondence to Bambu's
catalog ids lives in one generated file the app applies at the printer boundary — the next
section. Nothing under `resources/profiles/**` carries a `GF*` id today and nothing can be
exempted, so a `GF*` id appearing anywhere in the tree is a mistake, whoever wrote it.
- **Qidi (`QD_*`).** `QD_*` is a device-*protocol* namespace, not a preset id space: the
Qidi box path composes `QD_<series>_<vendor>_<typeidx>` ids at runtime (slot vendor and
type indices reported by the device, the series digit inferred client-side from the printer
model/name). Qidi presets carry ordinary minted `OF*` ids (generics share the OFL ids), so
a composed id matches no preset and the slot falls back to filament type; translating it to
the filament's id belongs in `QidiPrinterAgent`. The alternative — treating per-series
protocol ids as preset ids — would put one product under five ids (`QIDI PLA Rapido` would
be `QD_0_1_1` through `QD_4_1_1`), exactly the fragmentation the mint rule removes.
## The Bambu catalog map
Bambu's printers, its AMS and its cloud know only Bambu's own catalog ids. Our profiles carry
minted `OF` ids like every other vendor's, so one generated file records the correspondence and
the app applies it **only where an id crosses to or from a Bambu printer**.
**The file** is `resources/printers/bambu_filament_ids.json` — a header plus one row per
catalogued product, keyed by our id:
```json
{
"source": "https://github.com/bambulab/BambuStudio",
"bambustudio_commit": "66e405477",
"generated": "2026-09-04",
"filaments": {
"OFhuaUQB": { "bambu_id": "GFB00", "vendor": "Bambu Lab", "type": "ABS", "name": "Bambu ABS" }
}
}
```
It ships in `resources/printers/`, next to `filaments_blacklist.json` — deliberately not in
`resources/profiles/`, where the loader reads every top-level `.json` as a vendor index. It
holds 100 rows today, one per product BambuStudio ships, and the correspondence is
one-to-one in both directions.
**It is generated, never hand-edited.** `python scripts/update_bambu_filament_ids.py` rebuilds
it from **BambuStudio's own shipped BBL bundle** — a sparse shallow clone of upstream `master`,
or `--bambustudio-dir <a BambuStudio resources/profiles checkout>`. Our BBL bundle is a fork of
Bambu's, tuned and extended independently, so it is not the source of truth for Bambu's ids.
A row's key is the id the product's `(filament_vendor, filament_type, filament name)` triple
mints — the same id any bundle of ours carries for it, since the id is a function of the triple
alone; the row of a product we do not ship sits inert until some bundle claims that triple —
`OFdyfQvU` / `GFG03`, "Bambu PETG Matte", is such a row today.
**Regenerate it in the same commit as every BBL profile sync**, and read the drift report it
prints. Two lines, both informational, neither blocking the write:
```text
upstream ships 'Bambu PETG Matte' (Bambu Lab/PETG), we ship nothing with that identity
Orca BBL filaments with no row: 135 Orca-only product(s)
```
The first names each upstream product our BBL bundle has no same-identity filament for —
sometimes a genuinely missing product, sometimes a name drift a follow-up rename would
converge. The second counts our own BBL filaments that matched no row: 135 of 234 today, of
which 109 send an `OF` id on the wire and 26 already rode `OF` ids inherited from the
OrcaFilamentLibrary. **135 is the number to expect at every regeneration** — 109 was the
one-off size of the transition and stopped being computable from the tree once the BBL bundle
was re-minted, so do not "fix" the report to print it.
**Check 6** lives in `check_filament_ids`, so profile CI runs it alongside the other five. It
holds the file to its contract: it parses, carries `source` / `bambustudio_commit` /
`generated`, keys only `OF`-format ids, maps each Bambu id at most once, and — for every row
whose key the tree actually claims — agrees with the tree on that id's `(vendor, type, name)`
triple. A row for a product we do not ship is skipped, not an error. The remedy it prints is
always the same: regenerate the map and commit the diff for review.
### The runtime rule: swap on hit
Outbound, our id with a row becomes Bambu's; inbound, Bambu's id with a row becomes ours.
Everything else is forwarded untouched — an `OF` id with no row, a Bambu id for a product we do
not ship, a `P`-hex user id, `"null"`, an empty string. Translation is confined to the
boundary: nothing between the boundaries ever holds a Bambu id.
Translating one value is a capability of the printer agent: `IPrinterAgent` declares
`to_orca_filament_id` and `from_orca_filament_id` returning their argument, and `BBLPrinterAgent`
overrides them with Bambu's map, so an agent whose printers already speak our ids inherits the
identity default and translates nothing. `NetworkAgent` forwards both to the live agent, so the
comparison sites below reach them through `wxGetApp().getAgent()` and leave an id untranslated
while no agent is live. Whole documents are Bambu's business alone:
`BBLPrinterAgent::to_orca_payload` and `from_orca_payload` rewrite every string under
`tray_info_idx`, `filament_id` or `filamentId` at any depth; text that does not parse, or carries
none of those keys, comes back unchanged. The map is loaded once, lazily; a missing or malformed
file degrades to identity with a log line rather than failing.
| Boundary | Where it translates |
| --- | --- |
| Everything the agent sends | `BBLPrinterAgent::send_message` and `send_message_to_printer`, plus `PrintParams::ams_mapping_info` in `dispatch_start` — the funnel all five `start_*` calls share |
| Everything the agent receives | `set_on_message_fn` and `set_on_local_message_fn` wrap their callback, so `MachineObject::parse_json` and everything downstream see our ids only |
| 3mf export | `Plater::export_3mf` writes Bambu's ids into `slice_info.config`, gated on `preset_bundle.is_bbl_vendor()` — the printer reads that file and knows only its own catalog, and no other vendor's export is affected. The CLI has its own writer in `OrcaSlicer.cpp`; it does the same, gated on the `printer_model` prefix that already decides `Print::is_BBL_printer()` for that run |
| Project ingest | `Plater::priv::load_files` reverse-maps the project's `filament_ids` before the bundle ingests them, so a project saved by an older Orca or by BambuStudio still resolves the same presets |
| Prints from the printer's SD card | `SelectMachineDialog::update_print_required_data` reverse-maps each plate's slice-info ids as it adopts the plates, so the AMS mapping dialog pairs them with trays |
| Bambu-specific comparisons | `CalibUtils.cpp`, `DeviceManager.cpp`, `DeviceCore/DevFilaSystem.cpp`, `DeviceCore/DevFilaBlackList.cpp`, `SelectMachine.cpp`, `AMSDryControl.cpp`, `AMSMaterialsSetting.cpp`, `PresetComboBoxes.cpp`, `ColorDecomposeSupport.cpp` |
That last row is the rule to follow when a new Bambu-specific behaviour is added: **translate
the value you are about to compare, never the table you compare it against.** The shipped data
those sites read is Bambu's and stays verbatim — `white_fila_ids` in
`resources/printers/filaments_blacklist.json`, the calibration id lists in
`resources/printers/<model>.json`, `fila_id` in
`resources/profiles/BBL/filament/filaments_color_codes.json`.
`tests/slic3rutils/test_bambu_filament_ids.cpp` covers the lookups, the payload rewrite and the
Bambu-specific rules. `orcaslicer_discover_tests` registers a Catch2 tag as a CTest **label**,
not as part of the test name, so `-R` matches nothing here and the filter is `-L`:
```bash
ctest --test-dir <build dir>/tests/slic3rutils -L BambuFilamentIds
```
### Three places the map deliberately does not reach
The map and its lookups live in the GUI library, which libslic3r cannot link against and which a
GUI-less build does not link at all. Three consequences are known and documented; none is worth
pulling the map down into libslic3r for.
- **The support display type in `PrintConfig.cpp`.** `DynamicPrintConfig::get_filament_type`
picks `PLA-S` / `Sup.PLA` and `PA-S` / `Sup.PA` for a support filament by testing
`filament_id` against `GFS00` and `GFS01`, and otherwise falls back on `filament_type` — a
fallback that returns those same two pairs for `"PLA"` and `"PA"`. Bambu Support W inherits
`fdm_filament_pla` and Bambu Support G inherits `fdm_filament_pa`, so with their `OF` ids the
fallback produces exactly what the id branches produced. (The only config that ever carries a
singular `filament_id` key is the AMS tray config built in `Plater.cpp`, and that one never
reaches this function.) These two lines are the only mention of a Bambu id anywhere in
libslic3r, and they need no change.
- **Config imports.** `PresetBundle::import_presets` (File ▸ Import ▸ Import Configs, for
`.json` / `.zip` / `.orca_filament` / `.orca_printer` / `.orca_bundle`) and
`PresetBundle::load_config_file` (the CLI's `--load-settings` of a G-code file with an
embedded config) both parse inside libslic3r, out of the GUI's reach, so a Bambu id carried
in such a file lands on the imported preset untranslated. The effect is bounded: that preset
does not auto-match an AMS tray while the stale id is live, and the id does not survive
being saved — `Preset::save` writes a `filament_id` key only for a preset whose `inherits` is
empty, and on the next load an inheriting preset takes its parent's id. A known gap, and not
a regression: nothing forwarded a stale id before either.
- **A build configured without the GUI.** `target_link_libraries(OrcaSlicer libslic3r_gui)` sits
inside `if (SLIC3R_GUI)` in `src/CMakeLists.txt`, so the lookups are not linkable when the GUI
is off. The CLI's 3mf writer in `src/OrcaSlicer.cpp` therefore guards its translation with
`#ifdef SLIC3R_GUI`, and a 3mf that such a build slices for a Bambu printer carries our `OF`
ids in `slice_info.config` rather than Bambu's. Every shipped build enables the GUI, so this
reaches only a purpose-built GUI-less binary.
One more thing worth recording before it is rediscovered:
`SyncAmsInfoDialog::update_print_required_data` is a structural twin of the SD-card function
above and carries no translation. It has no callers today and its plate list is only ever read
for `printer_model_id`, so it is not a live gap — but wiring it up without adding the reverse
map would silently reproduce the bug.
## How CI enforces this
Profile CI (`check_profiles.yml`) runs `check_filament_ids()` tree-wide via
`scripts/orca_extra_profile_check.py`. Its ground truth is
**`scripts/filament_id_snapshot.json` — the sanctioned state**: the id state derived from the
tree must equal the snapshot exactly, in both directions. Any change to the id landscape
therefore surfaces as a diff to that file, and **that snapshot diff is what maintainers review
and gate in a PR**. Never edit the snapshot by hand — `--update-snapshot` regenerates it
deterministically (running it twice changes nothing). The snapshot holds one map, `ids`: each
entry is the product the id is minted from (`filament_vendor`, `filament_type`, `name`) and the
`filaments` claiming it (`Vendor/Filament`), and it sanctions *state*, never exceptions: no check
consults it to excuse a preset from a rule, and there is no grandfather list of any kind.
The checks, in brief:
- **Format** — every id occurring in the tree is `OF` + 6 base62 chars. No exceptions: not a
snapshot entry, not BBL.
- **Snapshot equality** — tree claims == snapshot claims **and** each id's declared triple ==
its snapshot entry, both directions: any `filament_vendor`/`filament_type`/name change
surfaces as a snapshot diff.
- **Identity** — the id is a function of the triple alone. A declared `OF*` id must equal the
one id its declarer's own triple mints, with no second acceptable value; the id an
instantiated preset *inherits* must equal the mint of *its* own triple, however it inherits
it (a root, a real filament, a library preset — structure rule 1); and every instantiated
system filament must resolve an effective id at all (recall: an id-less one is a hard load
error in C++ that discards the whole vendor bundle); and no two products mint one id (a
base62 collision, resolved by renaming one of them). The errors print the expected id.
- **Reserved namespaces** — `GF*`, `QD_*`, `P<7-hex>` or `"null"` claimed by any vendor,
BBL and Qidi included.
- **Triple integrity** — every declarer must resolve a non-empty `filament_vendor` and
`filament_type` (generics use `"Generic"`), and all declarers of one filament within a
bundle must agree on the triple.
- **Bambu catalog map** — `resources/printers/bambu_filament_ids.json` parses, carries its
`source` / `bambustudio_commit` / `generated` header, keys only `OF`-format ids, maps each
Bambu id at most once, and agrees with the tree on the triple of every row whose key the
tree claims. See [The Bambu catalog map](#the-bambu-catalog-map); the remedy is always to
regenerate, never to hand-edit.
A profile that declares a **reserved-namespace** id — `GF*`, `QD_*` or `P<7-hex>`, whatever
its vendor — cannot pass the format check, so `--update-snapshot` refuses to sanction it
rather than hide the mistake until CI. For a Bambu-cataloged product, the catalog map is where
the correspondence belongs. Any other new sharing via a *declared* id is caught by the identity
check; sharing through inheritance carries no declaration to check and surfaces only as a new
claim in the snapshot diff — which is exactly why that diff is the gate.
`orca_extra_profile_check.py` separately holds every declared id to the AMS 8-character limit,
tree-wide and for every vendor alike, scoped to the presets a vendor's index actually
references (a file the index never loads cannot break AMS matching).
Complementing the Python checks, CI also runs the C++ profile validator with `-f`
(`check_filament_subtypes`): it loads the bundle exactly as the app does and flags any printer
for which two or more compatible filament presets share one `filament_id` — the runtime-shaped
ambiguity check behind structure rule 3.
## FAQ
- **A new color of an existing product?** Never a new id — colors are not filaments.
- **A second diameter (1.75 mm and 2.85 mm) of the same product?** A sibling filament with its
own id: two diameters are separately selectable spool products.
- **A high-speed tune of an existing material for another printer model?** Same filament:
keep the base name and inherit its root; no id key needed.
- **A tuned generic ("our profile for Generic PLA")?** Inherit `Generic PLA @System`, keep the
`Generic PLA` base name, set `compatible_printers`; no id key needed.
- **A branded filament that borrows a generic's settings?** Fine — inherit `Generic X @System`
(or any real filament) for the settings and declare the id of your own filament; run
`python scripts/orca_id_tool.py --generate` to mint it. Inheritance never changes the id.
- **I need to fix a filament's `filament_vendor` or `filament_type`.** Fix the config, run
`--generate --vendor <Vendor>` (preview with `--dry-run`), then `--update-snapshot`, and commit
the profile and snapshot diffs together. The id re-derives from the corrected identity, and
nothing forwards the old value, so a tray or record still holding it falls back to matching by
filament type.
- **I need to rename a filament.** Rename the presets (adding `renamed_from`, which keeps the
preset *name* resolving), then `--generate --vendor <Vendor>` (preview with `--dry-run`), then
`--update-snapshot`. The id follows the new filament name; as with any identity fix, the old id
is not forwarded.
- **Can I reuse a `QD_*` id for a Qidi profile?** No — nobody can. It is the device protocol's
own id space: the box composes those values at runtime and no preset carries one. Author
Qidi filaments like any other vendor's.
- **CI says my filament needs an id.** Run `python scripts/orca_id_tool.py --generate`, then
`--update-snapshot`, and commit both diffs. Do not type an id by hand.
For general profile authoring, see the profile development guide on the
[OrcaSlicer wiki](https://www.orcaslicer.com/wiki).

View File

@@ -1,111 +0,0 @@
# Move `wxInspectable` into `DPIAware` — Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Move `wxInspector::wxInspectable` from individual leaf classes into the common `DPIAware<P>` template so every DPIAware widget is automatically inspectable and gets the inspector keyboard shortcut.
**Architecture:** `DPIAware<P>` gains `wxInspector::wxInspectable` as a second base class and calls `SetupInspectorAccelerator(this)` in its constructor. `DPIDialog` and `MainFrame` drop their now-redundant `wxInspectable` inheritance and `SetupInspectorAccelerator` calls.
**Tech Stack:** C++17, wxWidgets, wxInspector
## Global Constraints
- Build with `D:\VisualStudio\2026\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe`
- Use `--config RelWithDebInfo` for all builds
- Cross-platform: must compile on Windows, macOS, and Linux
- Match existing code style: PascalCase classes, `#pragma once`
- Do NOT commit files under `.superpowers/`
- Do NOT commit `task.md`
---
### Task 1: Move `wxInspectable` and `SetupInspectorAccelerator` into `DPIAware<P>`
**Files:**
- Modify: `src/slic3r/GUI/GUI_Utils.hpp:92` (DPIAware template — add wxInspectable base + SetupInspectorAccelerator call)
- Modify: `src/slic3r/GUI/GUI_Utils.hpp:276` (DPIDialog — drop wxInspectable + SetupInspectorAccelerator)
- Modify: `src/slic3r/GUI/MainFrame.hpp:96` (MainFrame — drop wxInspectable)
- Modify: `src/slic3r/GUI/MainFrame.cpp:304` (MainFrame constructor — drop SetupInspectorAccelerator)
**Interfaces:**
- Consumes: Nothing (standalone refactor)
- Produces: All DPIAware widgets automatically inherit `wxInspector::wxInspectable` and get Ctrl+Shift+I accelerator
- [ ] **Step 1: Add `wxInspectable` to `DPIAware<P>` and call `SetupInspectorAccelerator`**
In `src/slic3r/GUI/GUI_Utils.hpp`, line 92, change the base class:
```cpp
// Before:
template<class P> class DPIAware : public P
// After:
template<class P> class DPIAware : public P, public wxInspector::wxInspectable
```
In the constructor body of `DPIAware<P>`, after `this->CenterOnParent();` (currently line 110), add:
```cpp
SetupInspectorAccelerator(this);
```
(`<wx/inspector/inspector.h>` is already included at line 23.)
- [ ] **Step 2: Remove redundant `wxInspectable` and `SetupInspectorAccelerator` from `DPIDialog`**
In `src/slic3r/GUI/GUI_Utils.hpp`, line 276, change:
```cpp
// Before:
class DPIDialog : public DPIAware<wxDialog>, public wxInspector::wxInspectable
// After:
class DPIDialog : public DPIAware<wxDialog>
```
In the `DPIDialog` constructor body, remove the `SetupInspectorAccelerator(this);` line (currently line 286). The rest of the constructor stays.
- [ ] **Step 3: Remove redundant `wxInspectable` from `MainFrame`**
In `src/slic3r/GUI/MainFrame.hpp`, line 96, change:
```cpp
// Before:
class MainFrame : public DPIFrame, public wxInspector::wxInspectable
// After:
class MainFrame : public DPIFrame
```
`MainFrame` now gets `wxInspectable` through `DPIFrame``DPIAware<wxFrame>`.
- [ ] **Step 4: Remove redundant `SetupInspectorAccelerator` from `MainFrame` constructor**
In `src/slic3r/GUI/MainFrame.cpp`, line 304, remove the line:
```cpp
SetupInspectorAccelerator(this);
```
It is now called automatically by the `DPIAware<wxFrame>` constructor.
- [ ] **Step 5: Build to verify compilation**
```powershell
$cmakePath = "D:\VisualStudio\2026\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe"
& $cmakePath --build . --config RelWithDebInfo --target ALL_BUILD -- -m
```
Expected: Build succeeds with zero new errors or warnings.
- [ ] **Step 6: Commit**
```bash
git add src/slic3r/GUI/GUI_Utils.hpp src/slic3r/GUI/MainFrame.hpp src/slic3r/GUI/MainFrame.cpp
git commit -m "refactor: move wxInspectable and SetupInspectorAccelerator into DPIAware
DPIAware<P> now inherits wxInspector::wxInspectable and calls
SetupInspectorAccelerator in its constructor, making all DPIAware
widgets automatically appear in the inspector tree with the
Ctrl+Shift+I shortcut. Remove redundant wxInspectable inheritance
and SetupInspectorAccelerator calls from DPIDialog and MainFrame.
Co-Authored-By: Claude <noreply@anthropic.com>"
```

View File

@@ -1,753 +0,0 @@
# wxInspector Plugins for OrcaSlicer — Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Build two wxInspector plugins (DPIAware + CustomWidgets) that expose OrcaSlicer custom control properties in the inspector's property grid.
**Architecture:** Two plugins in a shared folder under `src/slic3r/Utils/wxInspectorPlugins/`. DPIAwarePlugin uses `dynamic_cast<DPIFrame*>/<DPIDialog*>` for detection; CustomWidgetsPlugin uses per-type `dynamic_cast`. Both registered as static singletons via a single inline function in `Registration.hpp`, called from `MainFrame` constructor.
**Tech Stack:** C++17, wxWidgets, wxInspector plugin API (`wx/inspector/plugin.h`, `wx/inspector/inspector.h`), OrcaSlicer custom widget headers
## Global Constraints
- Plugins placed under `src/slic3r/Utils/wxInspectorPlugins/`
- Build with `D:\VisualStudio\2026\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe`
- Minimal source changes: only trivial (one-line) getters/setters added to existing classes
- Cross-platform: must compile on Windows, macOS, and Linux
- Match existing code style: PascalCase classes, snake_case functions, `#pragma once`
---
### Task 1: Add getters/setters to existing Orca widget headers
**Files:**
- Modify: `src/slic3r/GUI/GUI_Utils.hpp` (DPIAware template — add 4 methods)
- Modify: `src/slic3r/GUI/Widgets/Button.hpp` (add 3 getters)
- Modify: `src/slic3r/GUI/Widgets/CheckBox.hpp` (add 1 getter)
- Modify: `src/slic3r/GUI/Widgets/TextInput.hpp` (add 1 getter)
- Modify: `src/slic3r/GUI/Widgets/LabeledStaticBox.hpp` (add 4 getter declarations)
- Modify: `src/slic3r/GUI/Widgets/LabeledStaticBox.cpp` (add 4 getter implementations)
**Interfaces:**
- Consumes: Nothing (prerequisite for all other tasks)
- Produces:
- `DPIAware<P>::set_scale_factor(float)`, `DPIAware<P>::set_prev_scale_factor(float)`, `DPIAware<P>::set_em_unit(int)`, `DPIAware<P>::force_rescale() const`
- `Button::GetStyle()`, `Button::GetType()`, `Button::IsSelected()`
- `CheckBox::IsHalfChecked()`
- `TextInput::GetCornerRadius()`
- `LabeledStaticBox::GetCornerRadius()`, `LabeledStaticBox::GetBorderWidth()`, `LabeledStaticBox::GetBorderColor()`, `LabeledStaticBox::GetScale()`
- [ ] **Step 1: Add DPIAware setters/getter in GUI_Utils.hpp**
After line 184 (`float prev_scale_factor() const { return m_prev_scale_factor; }`), add:
```cpp
void set_scale_factor(float v) { m_scale_factor = v; }
void set_prev_scale_factor(float v) { m_prev_scale_factor = v; }
void set_em_unit(int v) { m_em_unit = v; }
bool force_rescale() const { return m_force_rescale; }
```
- [ ] **Step 2: Add Button getters in Button.hpp**
After line 79 (`void SetSelected(bool selected = true) { m_selected = selected; }`), add:
```cpp
ButtonStyle GetStyle() const { return m_style; }
ButtonType GetType() const { return m_type; }
bool IsSelected() const { return m_selected; }
```
- [ ] **Step 3: Add CheckBox getter in CheckBox.hpp**
After line 16 (`void SetHalfChecked(bool value = true);`), add:
```cpp
bool IsHalfChecked() const { return m_half_checked; }
```
- [ ] **Step 4: Add TextInput getter in TextInput.hpp**
After line 44 (`void SetCornerRadius(double radius);`), add:
```cpp
int GetCornerRadius() const { return static_cast<int>(radius); }
```
(Note: `radius` is inherited from `StaticBox` which has it as a protected `double` member.)
- [ ] **Step 5: Add LabeledStaticBox getter declarations in LabeledStaticBox.hpp**
After line 46 (`bool Enable(bool enable) override;`), add:
```cpp
int GetCornerRadius() const { return m_radius; }
int GetBorderWidth() const { return m_border_width; }
StateColor GetBorderColor() const { return border_color; }
float GetScale() const { return m_scale; }
```
(Note: all of `m_radius`, `m_border_width`, `border_color`, `m_scale` are protected members, accessible to inline methods.)
- [ ] **Step 6: Commit**
```bash
git add src/slic3r/GUI/GUI_Utils.hpp src/slic3r/GUI/Widgets/Button.hpp src/slic3r/GUI/Widgets/CheckBox.hpp src/slic3r/GUI/Widgets/TextInput.hpp src/slic3r/GUI/Widgets/LabeledStaticBox.hpp
git commit -m "feat: add getters/setters for wxInspector plugin access
Add minimal public accessors to DPIAware (set_scale_factor,
set_prev_scale_factor, set_em_unit, force_rescale), Button
(GetStyle, GetType, IsSelected), CheckBox (IsHalfChecked),
TextInput (GetCornerRadius), and LabeledStaticBox
(GetCornerRadius, GetBorderWidth, GetBorderColor, GetScale)."
```
---
### Task 2: Create Registration helper header
**Files:**
- Create: `src/slic3r/Utils/wxInspectorPlugins/Registration.hpp`
**Interfaces:**
- Consumes: Nothing (forward-declares plugin classes)
- Produces: `RegisterOrcaInspectorPlugins()`
- [ ] **Step 1: Create directory**
```bash
mkdir -p src/slic3r/Utils/wxInspectorPlugins
```
- [ ] **Step 2: Write Registration.hpp**
```cpp
#pragma once
namespace wxInspector {
class wxInspectorPlugin;
void RegisterPlugin(wxInspectorPlugin* plugin);
}
// Forward declare our plugins
class DPIAwarePlugin;
class CustomWidgetsPlugin;
inline void RegisterOrcaInspectorPlugins()
{
static DPIAwarePlugin dpiaware;
static CustomWidgetsPlugin customWidgets;
wxInspector::RegisterPlugin(&dpiaware);
wxInspector::RegisterPlugin(&customWidgets);
}
```
- [ ] **Step 3: Commit**
```bash
git add src/slic3r/Utils/wxInspectorPlugins/Registration.hpp
git commit -m "feat: add wxInspector plugin registration helper
Add RegisterOrcaInspectorPlugins() inline function that creates
and registers the DPIAwarePlugin and CustomWidgetsPlugin as
static instances (matching wxInspector's built-in pattern)."
```
---
### Task 3: Create DPIAwarePlugin
**Files:**
- Create: `src/slic3r/Utils/wxInspectorPlugins/DPIAwarePlugin.hpp`
- Create: `src/slic3r/Utils/wxInspectorPlugins/DPIAwarePlugin.cpp`
**Interfaces:**
- Consumes: Task 1 (DPIAware getters/setters), Task 2 (registration pattern)
- Produces: `class DPIAwarePlugin : public wxInspector::wxInspectorPlugin`
- [ ] **Step 1: Write DPIAwarePlugin.hpp**
```cpp
#pragma once
#include <wx/inspector/plugin.h>
class DPIAwarePlugin : public wxInspector::wxInspectorPlugin
{
public:
wxString GetName() const override;
bool CanProvideProperties(wxClassInfo* info) override;
wxVector<wxInspector::PropertyDef> GetProperties(
wxInspector::InspectableObject& obj) override;
};
```
- [ ] **Step 2: Write DPIAwarePlugin.cpp**
```cpp
#include "DPIAwarePlugin.hpp"
#include "slic3r/GUI/GUI_Utils.hpp" // DPIFrame, DPIDialog, DPIAware<P>
#include <wx/window.h>
namespace {
template<typename T>
void addDPIProps(T* dpi, wxVector<wxInspector::PropertyDef>& props)
{
using namespace wxInspector;
props.push_back({"Scale Factor", "DPI Scaling", PropertyType::String,
wxString::Format("%.2f", dpi->scale_factor()), false, {},
[dpi]() { return wxString::Format("%.2f", dpi->scale_factor()); },
[dpi](const wxString& v) {
double val;
if (wxSscanf(v, "%lf", &val) != 1) return false;
dpi->set_scale_factor((float) val);
return true;
}});
props.push_back({"Prev Scale Factor", "DPI Scaling", PropertyType::String,
wxString::Format("%.2f", dpi->prev_scale_factor()), false, {},
[dpi]() { return wxString::Format("%.2f", dpi->prev_scale_factor()); },
[dpi](const wxString& v) {
double val;
if (wxSscanf(v, "%lf", &val) != 1) return false;
dpi->set_prev_scale_factor((float) val);
return true;
}});
props.push_back({"EM Unit", "DPI Scaling", PropertyType::Integer,
wxString::Format("%d", dpi->em_unit()), false, {},
[dpi]() { return wxString::Format("%d", dpi->em_unit()); },
[dpi](const wxString& v) {
long val;
if (!v.ToLong(&val)) return false;
dpi->set_em_unit((int) val);
return true;
}});
props.push_back({"Normal Font", "DPI Scaling", PropertyType::ReadOnly,
dpi->normal_font().GetNativeFontInfoDesc(), true, {},
[dpi]() { return dpi->normal_font().GetNativeFontInfoDesc(); },
nullptr});
props.push_back({"Force Rescale", "DPI Scaling", PropertyType::Boolean,
dpi->force_rescale() ? "true" : "false", true, {},
[dpi]() { return dpi->force_rescale() ? "true" : "false"; },
nullptr});
}
} // anonymous namespace
wxString DPIAwarePlugin::GetName() const
{
return "OrcaDPIAware";
}
bool DPIAwarePlugin::CanProvideProperties(wxClassInfo* info)
{
return info->IsKindOf(CLASSINFO(wxWindow));
}
wxVector<wxInspector::PropertyDef> DPIAwarePlugin::GetProperties(
wxInspector::InspectableObject& obj)
{
wxVector<wxInspector::PropertyDef> props;
wxWindow* win = obj.AsWindow();
if (!win) return props;
if (auto* frame = dynamic_cast<DPIFrame*>(win)) {
addDPIProps(frame, props);
} else if (auto* dlg = dynamic_cast<DPIDialog*>(win)) {
addDPIProps(dlg, props);
}
return props;
}
```
- [ ] **Step 3: Commit**
```bash
git add src/slic3r/Utils/wxInspectorPlugins/DPIAwarePlugin.hpp src/slic3r/Utils/wxInspectorPlugins/DPIAwarePlugin.cpp
git commit -m "feat: add DPIAware wxInspector plugin
Exposes DPI scaling properties (scale_factor, prev_scale_factor,
em_unit, normal_font, force_rescale) on DPIFrame and DPIDialog
widgets. Uses dynamic_cast for detection and a template helper
to capture the correct static type for lambda accessors."
```
---
### Task 4: Create CustomWidgetsPlugin
**Files:**
- Create: `src/slic3r/Utils/wxInspectorPlugins/CustomWidgetsPlugin.hpp`
- Create: `src/slic3r/Utils/wxInspectorPlugins/CustomWidgetsPlugin.cpp`
**Interfaces:**
- Consumes: Task 1 (all widget getters), Task 2 (registration pattern)
- Produces: `class CustomWidgetsPlugin : public wxInspector::wxInspectorPlugin`
- [ ] **Step 1: Write CustomWidgetsPlugin.hpp**
```cpp
#pragma once
#include <wx/inspector/plugin.h>
class CustomWidgetsPlugin : public wxInspector::wxInspectorPlugin
{
public:
wxString GetName() const override;
bool CanProvideProperties(wxClassInfo* info) override;
wxVector<wxInspector::PropertyDef> GetProperties(
wxInspector::InspectableObject& obj) override;
private:
void addButtonProps(class Button* btn,
wxVector<wxInspector::PropertyDef>& props);
void addCheckBoxProps(class CheckBox* cb,
wxVector<wxInspector::PropertyDef>& props);
void addTextInputProps(class TextInput* ti,
wxVector<wxInspector::PropertyDef>& props);
void addSwitchButtonProps(class SwitchButton* sb,
wxVector<wxInspector::PropertyDef>& props);
void addProgressBarProps(class ProgressBar* pb,
wxVector<wxInspector::PropertyDef>& props);
void addLabelProps(class Label* lbl,
wxVector<wxInspector::PropertyDef>& props);
void addLabeledStaticBoxProps(class LabeledStaticBox* lsb,
wxVector<wxInspector::PropertyDef>& props);
};
```
- [ ] **Step 2: Write CustomWidgetsPlugin.cpp — includes and GetName/CanProvideProperties**
```cpp
#include "CustomWidgetsPlugin.hpp"
#include "slic3r/GUI/Widgets/Button.hpp"
#include "slic3r/GUI/Widgets/CheckBox.hpp"
#include "slic3r/GUI/Widgets/TextInput.hpp"
#include "slic3r/GUI/Widgets/SwitchButton.hpp"
#include "slic3r/GUI/Widgets/ProgressBar.hpp"
#include "slic3r/GUI/Widgets/Label.hpp"
#include "slic3r/GUI/Widgets/LabeledStaticBox.hpp"
#include <wx/window.h>
#include <wx/tglbtn.h>
wxString CustomWidgetsPlugin::GetName() const
{
return "OrcaCustomWidgets";
}
bool CustomWidgetsPlugin::CanProvideProperties(wxClassInfo* info)
{
return info->IsKindOf(CLASSINFO(wxWindow));
}
wxVector<wxInspector::PropertyDef> CustomWidgetsPlugin::GetProperties(
wxInspector::InspectableObject& obj)
{
wxVector<wxInspector::PropertyDef> props;
wxWindow* win = obj.AsWindow();
if (!win) return props;
if (auto* btn = dynamic_cast<Button*>(win))
addButtonProps(btn, props);
if (auto* cb = dynamic_cast<CheckBox*>(win))
addCheckBoxProps(cb, props);
if (auto* ti = dynamic_cast<TextInput*>(win))
addTextInputProps(ti, props);
if (auto* sb = dynamic_cast<SwitchButton*>(win))
addSwitchButtonProps(sb, props);
if (auto* pb = dynamic_cast<ProgressBar*>(win))
addProgressBarProps(pb, props);
if (auto* lbl = dynamic_cast<Label*>(win))
addLabelProps(lbl, props);
if (auto* lsb = dynamic_cast<LabeledStaticBox*>(win))
addLabeledStaticBoxProps(lsb, props);
return props;
}
```
- [ ] **Step 3: Write CustomWidgetsPlugin.cpp — addButtonProps**
```cpp
void CustomWidgetsPlugin::addButtonProps(Button* btn,
wxVector<wxInspector::PropertyDef>& props)
{
using namespace wxInspector;
wxVector<wxString> styleChoices;
styleChoices.push_back("Regular");
styleChoices.push_back("Confirm");
styleChoices.push_back("Alert");
styleChoices.push_back("Disabled");
auto styleToStr = [](ButtonStyle s) -> wxString {
switch (s) {
case ButtonStyle::Regular: return "Regular";
case ButtonStyle::Confirm: return "Confirm";
case ButtonStyle::Alert: return "Alert";
case ButtonStyle::Disabled: return "Disabled";
}
return "Regular";
};
props.push_back({"Button Style", "Orca Button", PropertyType::Choice,
styleToStr(btn->GetStyle()), false, styleChoices,
[btn, styleToStr]() { return styleToStr(btn->GetStyle()); },
[btn](const wxString& v) {
ButtonStyle s = ButtonStyle::Regular;
if (v == "Confirm") s = ButtonStyle::Confirm;
else if (v == "Alert") s = ButtonStyle::Alert;
else if (v == "Disabled") s = ButtonStyle::Disabled;
btn->SetStyle(s, btn->GetType());
return true;
}});
wxVector<wxString> typeChoices;
typeChoices.push_back("Compact");
typeChoices.push_back("Window");
typeChoices.push_back("Choice");
typeChoices.push_back("Parameter");
typeChoices.push_back("Icon");
typeChoices.push_back("Expanded");
auto typeToStr = [](ButtonType t) -> wxString {
switch (t) {
case ButtonType::Compact: return "Compact";
case ButtonType::Window: return "Window";
case ButtonType::Choice: return "Choice";
case ButtonType::Parameter: return "Parameter";
case ButtonType::Icon: return "Icon";
case ButtonType::Expanded: return "Expanded";
}
return "Compact";
};
props.push_back({"Button Type", "Orca Button", PropertyType::Choice,
typeToStr(btn->GetType()), false, typeChoices,
[btn, typeToStr]() { return typeToStr(btn->GetType()); },
[btn](const wxString& v) {
ButtonType t = ButtonType::Compact;
if (v == "Window") t = ButtonType::Window;
else if (v == "Choice") t = ButtonType::Choice;
else if (v == "Parameter") t = ButtonType::Parameter;
else if (v == "Icon") t = ButtonType::Icon;
else if (v == "Expanded") t = ButtonType::Expanded;
btn->SetStyle(btn->GetStyle(), t);
return true;
}});
props.push_back({"Selected", "Orca Button", PropertyType::Boolean,
btn->IsSelected() ? "true" : "false", false, {},
[btn]() { return btn->IsSelected() ? "true" : "false"; },
[btn](const wxString& v) {
btn->SetSelected(v == "true");
btn->Refresh();
return true;
}});
}
```
- [ ] **Step 4: Write CustomWidgetsPlugin.cpp — addCheckBoxProps**
```cpp
void CustomWidgetsPlugin::addCheckBoxProps(CheckBox* cb,
wxVector<wxInspector::PropertyDef>& props)
{
using namespace wxInspector;
props.push_back({"Half Checked", "Orca CheckBox", PropertyType::Boolean,
cb->IsHalfChecked() ? "true" : "false", false, {},
[cb]() { return cb->IsHalfChecked() ? "true" : "false"; },
[cb](const wxString& v) {
cb->SetHalfChecked(v == "true");
return true;
}});
}
```
- [ ] **Step 5: Write CustomWidgetsPlugin.cpp — addTextInputProps**
```cpp
void CustomWidgetsPlugin::addTextInputProps(TextInput* ti,
wxVector<wxInspector::PropertyDef>& props)
{
using namespace wxInspector;
props.push_back({"Label", "Orca TextInput", PropertyType::String,
ti->GetLabel(), false, {},
[ti]() { return ti->GetLabel(); },
[ti](const wxString& v) { ti->SetLabel(v); return true; }});
props.push_back({"Text Value", "Orca TextInput", PropertyType::String,
ti->GetTextCtrl()->GetValue(), false, {},
[ti]() { return ti->GetTextCtrl()->GetValue(); },
[ti](const wxString& v) { ti->GetTextCtrl()->SetValue(v); return true; }});
props.push_back({"Corner Radius", "Orca TextInput", PropertyType::Integer,
wxString::Format("%d", ti->GetCornerRadius()), false, {},
[ti]() { return wxString::Format("%d", ti->GetCornerRadius()); },
[ti](const wxString& v) {
long val;
if (!v.ToLong(&val)) return false;
ti->SetCornerRadius((double) val);
ti->Refresh();
return true;
}});
}
```
- [ ] **Step 6: Write CustomWidgetsPlugin.cpp — addSwitchButtonProps**
```cpp
void CustomWidgetsPlugin::addSwitchButtonProps(SwitchButton* sb,
wxVector<wxInspector::PropertyDef>& props)
{
using namespace wxInspector;
props.push_back({"Value", "Orca SwitchButton", PropertyType::Boolean,
sb->GetValue() ? "true" : "false", false, {},
[sb]() { return sb->GetValue() ? "true" : "false"; },
[sb](const wxString& v) {
sb->SetValue(v == "true");
return true;
}});
}
```
(Note: `GetValue()` and `SetValue()` are inherited from `wxBitmapToggleButton``wxToggleButton`.)
- [ ] **Step 7: Write CustomWidgetsPlugin.cpp — addProgressBarProps**
```cpp
void CustomWidgetsPlugin::addProgressBarProps(ProgressBar* pb,
wxVector<wxInspector::PropertyDef>& props)
{
using namespace wxInspector;
props.push_back({"Proportion", "Orca ProgressBar", PropertyType::String,
wxString::Format("%.2f", pb->m_proportion), false, {},
[pb]() { return wxString::Format("%.2f", pb->m_proportion); },
[pb](const wxString& v) {
double val;
if (wxSscanf(v, "%lf", &val) != 1) return false;
pb->m_proportion = val;
pb->Refresh();
return true;
}});
props.push_back({"Show Number", "Orca ProgressBar", PropertyType::Boolean,
pb->m_shownumber ? "true" : "false", false, {},
[pb]() { return pb->m_shownumber ? "true" : "false"; },
[pb](const wxString& v) {
pb->m_shownumber = (v == "true");
pb->Refresh();
return true;
}});
}
```
(Note: `m_proportion` and `m_shownumber` are public members on `ProgressBar`.)
- [ ] **Step 8: Write CustomWidgetsPlugin.cpp — addLabelProps**
```cpp
void CustomWidgetsPlugin::addLabelProps(Label* lbl,
wxVector<wxInspector::PropertyDef>& props)
{
using namespace wxInspector;
bool isHyperlink = (lbl->GetWindowStyleFlag() & 0x0020) != 0; // LB_HYPERLINK
props.push_back({"Is Hyperlink", "Orca Label", PropertyType::Boolean,
isHyperlink ? "true" : "false", true, {},
[lbl]() {
return (lbl->GetWindowStyleFlag() & 0x0020) ? "true" : "false";
},
nullptr});
props.push_back({"Font Point Size", "Orca Label", PropertyType::ReadOnly,
wxString::Format("%d", lbl->GetFont().GetPointSize()), true, {},
[lbl]() {
return wxString::Format("%d", lbl->GetFont().GetPointSize());
},
nullptr});
}
```
- [ ] **Step 9: Write CustomWidgetsPlugin.cpp — addLabeledStaticBoxProps**
```cpp
void CustomWidgetsPlugin::addLabeledStaticBoxProps(LabeledStaticBox* lsb,
wxVector<wxInspector::PropertyDef>& props)
{
using namespace wxInspector;
props.push_back({"Corner Radius", "LabeledStaticBox", PropertyType::Integer,
wxString::Format("%d", lsb->GetCornerRadius()), false, {},
[lsb]() { return wxString::Format("%d", lsb->GetCornerRadius()); },
[lsb](const wxString& v) {
long val;
if (!v.ToLong(&val)) return false;
lsb->SetCornerRadius((int) val);
return true;
}});
props.push_back({"Border Width", "LabeledStaticBox", PropertyType::Integer,
wxString::Format("%d", lsb->GetBorderWidth()), false, {},
[lsb]() { return wxString::Format("%d", lsb->GetBorderWidth()); },
[lsb](const wxString& v) {
long val;
if (!v.ToLong(&val)) return false;
lsb->SetBorderWidth((int) val);
return true;
}});
// Border Color: display as hex string
wxColour bc = lsb->GetBorderColor().colorForStates(0);
props.push_back({"Border Color", "LabeledStaticBox", PropertyType::String,
bc.GetAsString(wxC2S_HTML_SYNTAX), false, {},
[lsb]() {
return lsb->GetBorderColor()
.colorForStates(0)
.GetAsString(wxC2S_HTML_SYNTAX);
},
[lsb](const wxString& v) {
wxColour c(v);
if (!c.IsOk()) return false;
lsb->SetBorderColor(StateColor(c));
return true;
}});
props.push_back({"Scale", "LabeledStaticBox", PropertyType::ReadOnly,
wxString::Format("%.2f", lsb->GetScale()), true, {},
[lsb]() { return wxString::Format("%.2f", lsb->GetScale()); },
nullptr});
}
```
- [ ] **Step 10: Commit**
```bash
git add src/slic3r/Utils/wxInspectorPlugins/CustomWidgetsPlugin.hpp src/slic3r/Utils/wxInspectorPlugins/CustomWidgetsPlugin.cpp
git commit -m "feat: add OrcaCustomWidgets wxInspector plugin
Exposes Orca-specific properties on 7 widget types:
- Button: Style, Type, Selected
- CheckBox: Half Checked
- TextInput: Label, Text Value, Corner Radius
- SwitchButton: Value
- ProgressBar: Proportion, Show Number
- Label: Is Hyperlink, Font Point Size
- LabeledStaticBox: Corner Radius, Border Width, Border Color, Scale
Each widget type uses dynamic_cast for safe detection."
```
---
### Task 5: Wire plugins into MainFrame and CMakeLists
**Files:**
- Modify: `src/slic3r/GUI/MainFrame.cpp` (add include + registration call)
- Modify: `src/slic3r/CMakeLists.txt` (add 4 source files)
**Interfaces:**
- Consumes: Tasks 1-4 (all plugins and registration helper)
- Produces: Registered plugins available at runtime, buildable project
- [ ] **Step 1: Add include in MainFrame.cpp**
After the existing includes (around line 30, near the other Utils includes), add:
```cpp
#include "slic3r/Utils/wxInspectorPlugins/Registration.hpp"
```
- [ ] **Step 2: Add registration call in MainFrame constructor**
After `SetupInspectorAccelerator(this);` (currently line ~303), add:
```cpp
RegisterOrcaInspectorPlugins();
```
- [ ] **Step 3: Add source files to CMakeLists.txt**
Find the `SLIC3R_GUI_SOURCES` list in `src/slic3r/CMakeLists.txt`. After the existing `Utils/*.cpp` entries (around line 650-754), add:
```cmake
Utils/wxInspectorPlugins/DPIAwarePlugin.hpp
Utils/wxInspectorPlugins/DPIAwarePlugin.cpp
Utils/wxInspectorPlugins/CustomWidgetsPlugin.hpp
Utils/wxInspectorPlugins/CustomWidgetsPlugin.cpp
Utils/wxInspectorPlugins/Registration.hpp
```
(Note: Add all 5 files — 2 .hpp + 2 .cpp + 1 Registration.hpp. wxWidgets cmake needs headers listed too for the resource system.)
- [ ] **Step 4: Commit**
```bash
git add src/slic3r/GUI/MainFrame.cpp src/slic3r/CMakeLists.txt
git commit -m "feat: wire wxInspector plugins into MainFrame and build
- Call RegisterOrcaInspectorPlugins() after SetupInspectorAccelerator
- Add all plugin source files to SLIC3R_GUI_SOURCES"
```
---
### Task 6: Build and verify
**Files:**
- None modified (verification only)
- [ ] **Step 1: Configure the build**
```powershell
$cmakePath = "D:\VisualStudio\2026\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe"
& $cmakePath --build . --config Debug --target ALL_BUILD -- -m
```
Expected: Build succeeds with zero errors and zero warnings from our new files.
- [ ] **Step 2: Fix any compilation errors**
If the build fails:
- Check that `#include` paths resolve (the `slic3r/GUI/…` relative paths use `src/` as the include root — verify this is set up in CMake via `include_directories`)
- Check that `ButtonStyle` and `ButtonType` enums are visible (they're defined in `Button.hpp`)
- Check that `StateColor` constructor from `wxColour` is valid (it has `StateColor(wxColour const&)`)
- Check that `LabeledStaticBox::GetBorderColor()` returns by value (StateColor copy is fine)
- On macOS: static box margin removal call needs `#ifdef __WXOSX__` guard
- [ ] **Step 3: Launch OrcaSlicer and verify inspector**
Launch the built OrcaSlicer, press Ctrl+Shift+I to open the inspector:
1. Select the MainFrame in the tree — verify "DPI Scaling" category appears with Scale Factor, Prev Scale Factor, EM Unit, Normal Font, Force Rescale
2. Select an Orca Button — verify "Orca Button" category appears
3. Select an Orca CheckBox — verify "Orca CheckBox" category appears
4. Edit a property value (e.g., Scale Factor) — verify the setter applies correctly
5. Select a LabeledStaticBox — verify corner radius, border width, border color, scale appear
- [ ] **Step 5: Commit (if fixes were needed) or mark complete**
```bash
git status
```
If clean: verification complete. If changes were made: `git add` and commit with fix message.

View File

@@ -1,376 +0,0 @@
# macOS FFmpeg Media Player Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Make macOS use the same FFmpeg-based media player (`wxMediaCtrl3` + `AVVideoDecoder`) as Windows/Linux, linking the static FFmpeg libraries from the deps build, and remove the old `wxMediaCtrl2.mm` BambuPlayer-based player.
**Architecture:** The new player is platform-neutral C++ already used on Linux/Windows. Enabling it on macOS is pure build wiring: compile `wxMediaCtrl3.cpp` + `AVVideoDecoder.cpp` on macOS, drop the `__WXMAC__` alias that redirects `wxMediaCtrl3` to the old `wxMediaCtrl2`, and link static FFmpeg (`libavcodec.a`/`libswscale.a`/`libavutil.a`) from the deps install. The Bambu stream API is dlsym'd at runtime from the network plugin (`libBambuSource.dylib`), which already exports it — no plugin changes needed. Rendering reuses the existing `wxImage``DrawBitmap` paint path (same as Linux).
**Tech Stack:** C++17, wxWidgets, CMake, FFmpeg 7.0.3 (libavcodec/libswscale/libavutil), macOS (Xcode generator), `deps/` ExternalProject build system.
## Global Constraints
- Branch: `dev/ffmpeg-player-macos`. Commit after every task.
- **Linux and Windows builds must not change** — the FFmpeg deps flag change is guarded by `APPLE`; Linux keeps `--enable-shared`, Windows keeps its prebuilt DLL zips.
- Static FFmpeg only on macOS: deps produce `libavcodec.a`/`libswscale.a`/`libavutil.a`; the app links those explicitly — the app binary must have **no** `libav*` dylib references (`otool -L` check).
- Follow existing code style: PascalCase classes, snake_case functions, C++17.
- No changes to `StatusPanel.cpp`, `MediaPlayCtrl.*`, or the BambuTunnel interface — the app already creates `wxMediaCtrl3` and uses only its public interface.
- The player cannot be unit-tested (hardware/plugin-dependent GUI code); verification is build-level, link-level, and manual runtime on a Mac.
- `localization/i18n/list.txt` references only `wxMediaCtrl2.cpp` (Win/Linux, stays) — no translation-list changes needed.
- Build dirs on the dev machine: main app = `build_arm64/` (Xcode generator, multi-config), deps = `deps/build/arm64/` (Unix Makefiles). App target name: `OrcaSlicer`. Substitute your own configured build dirs where noted.
---
### Task 1: Enable wxMediaCtrl3 on macOS and link static FFmpeg
**Files:**
- Modify: `src/slic3r/GUI/wxMediaCtrl3.h` (lines 1822: the `#ifdef __WXMAC__` alias branch)
- Modify: `src/slic3r/GUI/wxMediaCtrl3.cpp:13` (uncomment the event define)
- Modify: `src/slic3r/GUI/wxMediaCtrl2.cpp:101` (remove the event define)
- Modify: `src/slic3r/CMakeLists.txt` (APPLE source list ~lines 779792; FFmpeg link block ~lines 905910)
**Interfaces:**
- Consumes: nothing new (all classes already exist).
- Produces: `wxMediaCtrl3` class compiled on macOS with the same interface as Linux/Windows — `Load(wxURI)`, `Play()`, `Stop()`, `SetIdleImage(wxString)`, `GetState()`, `GetLastError()`, `GetVideoSize()`, event `EVT_MEDIA_CTRL_STAT` defined once in the lib (from `wxMediaCtrl3.cpp`).
- [ ] **Step 1: Remove the macOS alias in wxMediaCtrl3.h**
Current (lines 1623 of `src/slic3r/GUI/wxMediaCtrl3.h`):
```cpp
void wxMediaCtrl_OnSize(wxWindow * ctrl, wxSize const & videoSize, int width, int height);
#ifdef __WXMAC__
#include "wxMediaCtrl2.h"
#define wxMediaCtrl3 wxMediaCtrl2
#else
#define BAMBU_DYNAMIC
```
New:
```cpp
void wxMediaCtrl_OnSize(wxWindow * ctrl, wxSize const & videoSize, int width, int height);
#define BAMBU_DYNAMIC
```
Also remove the matching `#endif` that closed the `#else` branch (the one before the final `#endif /* wxMediaCtrl3_h */`), so the file's `#ifndef`/`#endif` guard pair stays balanced.
- [ ] **Step 2: Move the EVT_MEDIA_CTRL_STAT definition into wxMediaCtrl3.cpp**
In `src/slic3r/GUI/wxMediaCtrl3.cpp:13`, uncomment:
```cpp
//wxDEFINE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent);
```
becomes:
```cpp
wxDEFINE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent);
```
In `src/slic3r/GUI/wxMediaCtrl2.cpp:101`, delete:
```cpp
wxDEFINE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent);
```
(One definition total in the lib — `MediaPlayCtrl.cpp:59` binds this event on the media ctrl.)
- [ ] **Step 3: Update the APPLE source list in CMakeLists.txt**
In `src/slic3r/CMakeLists.txt`, the APPLE branch (currently compiles `wxMediaCtrl2.mm`, which becomes dead on macOS):
```cmake
GUI/wxMediaCtrl2.mm
GUI/wxMediaCtrl2.h
GUI/wxMediaCtrl3.h
)
```
becomes:
```cmake
GUI/AVVideoDecoder.cpp
GUI/AVVideoDecoder.hpp
GUI/wxMediaCtrl3.cpp
GUI/wxMediaCtrl3.h
)
```
(The `else ()` branch — Win/Linux — stays exactly as it is.)
- [ ] **Step 4: Link static FFmpeg on macOS**
In `src/slic3r/CMakeLists.txt`, the FFmpeg block (currently `if (NOT APPLE)`):
```cmake
if (NOT APPLE)
pkg_check_modules(LIBAV REQUIRED IMPORTED_TARGET
libavcodec
libswscale
libavutil
)
target_link_libraries(libslic3r_gui PkgConfig::LIBAV)
endif()
```
becomes:
```cmake
if (APPLE)
# Static FFmpeg from the deps install: nothing to bundle into the .app,
# no rpath/install_name handling. Order matters: avcodec -> swscale -> avutil.
find_library(LIBAVCODEC_LIBRARY NAMES libavcodec.a PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
find_library(LIBSWSCALE_LIBRARY NAMES libswscale.a PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
find_library(LIBAVUTIL_LIBRARY NAMES libavutil.a PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
target_link_libraries(libslic3r_gui ${LIBAVCODEC_LIBRARY} ${LIBSWSCALE_LIBRARY} ${LIBAVUTIL_LIBRARY})
target_include_directories(libslic3r_gui SYSTEM PRIVATE ${CMAKE_PREFIX_PATH}/include)
else ()
pkg_check_modules(LIBAV REQUIRED IMPORTED_TARGET
libavcodec
libswscale
libavutil
)
target_link_libraries(libslic3r_gui PkgConfig::LIBAV)
endif()
```
The deps install (`${CMAKE_PREFIX_PATH}/lib`) already contains the three `.a` files from the existing arm64 deps build — no deps rebuild needed for this task.
- [ ] **Step 5: Reconfigure and build the app**
Run (Xcode generator; `cmake` re-runs automatically on build):
```bash
cmake --build build_arm64 --config RelWithDebInfo --target OrcaSlicer
```
Expected: configure succeeds (no `pkg_check_modules` errors on macOS, `find_library` finds all three `.a` files), compile succeeds (`wxMediaCtrl3.cpp` and `AVVideoDecoder.cpp` compile on macOS without changes), link succeeds.
If CMake complains that `wxMediaCtrl3.h` is included but not in the source list or similar IDE-only warnings — ignore; headers in the list are cosmetic.
- [ ] **Step 6: Verify no dynamic FFmpeg dependency**
```bash
otool -L build_arm64/src/RelWithDebInfo/OrcaSlicer.app/Contents/MacOS/OrcaSlicer | grep -i "libav" || echo "OK: no dynamic FFmpeg"
```
Expected: prints `OK: no dynamic FFmpeg` (empty grep output). This is the whole point of static linking — nothing to bundle into the `.app`.
- [ ] **Step 7: Quick sanity — macOS unit tests still pass**
```bash
ctest --test-dir build_arm64/tests/libslic3r --output-on-failure
```
Expected: passes (add `-C RelWithDebInfo` if the multi-config generator requires it). If no tests were built in this build dir, build target `tests` first (`cmake --build build_arm64 --config RelWithDebInfo --target tests`).
- [ ] **Step 8: Commit**
```bash
git add src/slic3r/CMakeLists.txt src/slic3r/GUI/wxMediaCtrl3.h src/slic3r/GUI/wxMediaCtrl3.cpp src/slic3r/GUI/wxMediaCtrl2.cpp
git commit -m "feat: use FFmpeg media player on macOS with static FFmpeg"
```
---
### Task 2: Static-only FFmpeg in the macOS deps build
**Files:**
- Modify: `deps/FFMPEG/FFMPEG.cmake` (non-MSVC branch, APPLE section and CONFIGURE_COMMAND)
**Interfaces:**
- Consumes: nothing.
- Produces: a deps install on macOS containing only `libavcodec.a`, `libswscale.a`, `libavutil.a` (+ headers) — no `libav*` dylibs, so no bundling/rpath machinery is ever needed on macOS. Linux and Windows output are unchanged.
- [ ] **Step 1: Add the static flag variable**
In `deps/FFMPEG/FFMPEG.cmake`, inside the non-MSVC `else ()` branch, in the existing `if (APPLE)` block:
```cmake
if (APPLE)
set(_minos_cmd
"CFLAGS=-mmacosx-version-min=${DEP_OSX_TARGET}"
"LDFLAGS=-mmacosx-version-min=${DEP_OSX_TARGET}"
)
```
add after the `_minos_cmd` set:
```cmake
# Static FFmpeg: nothing to bundle into the .app, no rpath handling.
# Shared flags must come AFTER --enable-shared below so they win.
set(_link_cmd --enable-static --disable-shared)
```
and add a matching `else ()` after the `if (IS_CROSS_COMPILE) ... endif()` block inside that `if (APPLE)`, so non-Apple Unix keeps shared:
```cmake
else ()
set(_link_cmd --enable-shared)
endif ()
```
(If the existing `if (IS_CROSS_COMPILE)` block is the last thing inside `if (APPLE)`, the new `else ()` closes the `if (APPLE)` itself.)
- [ ] **Step 2: Use the variable in CONFIGURE_COMMAND**
In the `ExternalProject_Add(dep_FFMPEG ...)` configure command:
```cmake
"--prefix=${DESTDIR}"
--enable-shared
```
becomes:
```cmake
"--prefix=${DESTDIR}"
--enable-shared
${_link_cmd}
```
Order matters: `--enable-shared` comes first, then `--enable-static --disable-shared` (APPLE) or `--enable-shared` (Linux) — the last flag wins in FFmpeg configure.
- [ ] **Step 3: Rebuild the FFmpeg dep (slow — several minutes, run in background)**
The changed CONFIGURE_COMMAND invalidates the ExternalProject stamp, so this re-configures and rebuilds FFmpeg:
```bash
cmake --build deps/build/arm64 --target dep_FFMPEG
```
For a fully clean static-only check (removes the previous shared build tree, which can leave stale `.dylib` files behind in the in-source build):
```bash
rm -rf deps/build/arm64/dep_FFMPEG-prefix
cmake --build deps/build/arm64 --target dep_FFMPEG
```
- [ ] **Step 4: Verify the artifacts**
```bash
ls deps/build/arm64/dep_FFMPEG-prefix/src/dep_FFMPEG/libavcodec/*.a
ls deps/build/arm64/dep_FFMPEG-prefix/src/dep_FFMPEG/libavcodec/*.dylib 2>/dev/null || echo "OK: no dylibs"
```
Expected: `libavcodec.a` present, second command prints `OK: no dylibs`. Check `libavutil` and `libswscale` the same way.
- [ ] **Step 5: Verify the app still links against the static libs**
```bash
cmake --build build_arm64 --config RelWithDebInfo --target OrcaSlicer
otool -L build_arm64/src/RelWithDebInfo/OrcaSlicer.app/Contents/MacOS/OrcaSlicer | grep -i "libav" || echo "OK: no dynamic FFmpeg"
```
Expected: build succeeds, `OK: no dynamic FFmpeg`.
- [ ] **Step 6: Commit**
```bash
git add deps/FFMPEG/FFMPEG.cmake
git commit -m "build: build static-only FFmpeg for macOS deps"
```
---
### Task 3: Remove the old macOS player
**Files:**
- Delete: `src/slic3r/GUI/wxMediaCtrl2.mm`
- Delete: `src/slic3r/GUI/BambuPlayer/BambuPlayer.h` (and the empty `BambuPlayer/` dir)
- Modify: `src/slic3r/GUI/wxMediaCtrl2.h` (remove the `#ifdef __WXMAC__` section, lines 2260)
**Interfaces:**
- Consumes: Task 1 (macOS no longer references `wxMediaCtrl2` — nothing includes `wxMediaCtrl2.h` on macOS anymore; `wxMediaCtrl2` is never instantiated on any platform).
- Produces: a clean tree where the old BambuPlayer-based player is gone from macOS. The `BambuPlayer` ObjC class itself remains inside the network plugin (external prebuilt binary) — only the GUI-side consumer is removed.
- [ ] **Step 1: Delete the old player files**
```bash
git rm src/slic3r/GUI/wxMediaCtrl2.mm
git rm src/slic3r/GUI/BambuPlayer/BambuPlayer.h
rmdir src/slic3r/GUI/BambuPlayer 2>/dev/null || true
```
- [ ] **Step 2: Strip the __WXMAC__ section from wxMediaCtrl2.h**
In `src/slic3r/GUI/wxMediaCtrl2.h`, remove the entire macOS branch of the `#ifdef __WXMAC__` guard — from `#ifdef __WXMAC__` (line 22) through the closing `};` of the mac class (line 60), and the `#else` marker — leaving only the non-mac `class wxMediaCtrl2 : public wxMediaCtrl { ... };` definition followed by the final `#endif /* wxMediaCtrl2_h */`. The resulting file keeps its `#ifndef`/`#endif` include guard pair balanced.
The file stays on disk because Win/Linux compile `wxMediaCtrl2.cpp`, which includes it.
- [ ] **Step 3: Grep for leftover references**
```bash
grep -rn "wxMediaCtrl2.mm\|BambuPlayer/BambuPlayer.h\|BambuPlayer" src/slic3r --include="*.cpp" --include="*.h" --include="*.mm" --include="*.txt"
```
Expected: no hits in `src/slic3r/GUI` (ignore `localization/i18n/list.txt:196`, which lists the Win/Linux `wxMediaCtrl2.cpp` and stays).
- [ ] **Step 4: Rebuild the app**
```bash
cmake --build build_arm64 --config RelWithDebInfo --target OrcaSlicer
```
Expected: configure + compile + link succeed with the deleted files gone.
- [ ] **Step 5: Commit**
```bash
git add -A src/slic3r/GUI
git commit -m "refactor: remove old BambuPlayer-based media player from macOS"
```
---
### Task 4: Runtime verification on hardware
**Files:** none — manual verification.
**Interfaces:** consumes all prior tasks. Final gate: the new player must actually stream on a Mac.
- [ ] **Step 1: Launch the freshly built app**
```bash
open build_arm64/src/RelWithDebInfo/OrcaSlicer.app
```
Expected: app launches normally; no crash in the network/device subsystem.
- [ ] **Step 2: Load the network plugin and open the Device tab**
Log in / ensure the network plugin (`libBambuSource.dylib`) loads, select a printer, open the Device tab (camera monitoring panel).
Expected: the camera preview area shows the idle image initially (no crash — this exercises `wxMediaCtrl3::SetIdleImage` and the `wxImage` load path on macOS for the first time).
- [ ] **Step 3: Start the stream and watch it render**
Click play / wait for `MediaPlayCtrl` to start the stream.
Expected: live video renders in the panel. Check the console/log output (`BOOST_LOG` goes to the terminal if run from it, or check the log file):
- `stat_log ...` lines appear (the `EVT_MEDIA_CTRL_STAT` path is live — proves the Bambu C API dlsym worked from `libBambuSource.dylib`);
- no repeated decode/error messages like `AVVideoDecoder: ...` or `can not find function ...` (proves `StaticBambuLib::get` resolved all Bambu functions);
- Stop/Play toggle works; idle image reappears on stop;
- window resize keeps aspect ratio (exercises `DoSetSize`/`adjust_frame_size`/`paintEvent`).
- [ ] **Step 4: Confirm the old player is really gone**
Expected: nothing in the logs references `BambuPlayer` (the ObjC class is no longer dlsym'd); the video path is entirely `wxMediaCtrl3` + `AVVideoDecoder`.
If a printer is unavailable, at minimum verify Steps 12 (launch + idle image) and note in the PR that live-stream verification needs hardware.
- [ ] **Step 5: Final review pass**
```bash
git log --oneline -6
git show --stat HEAD # and each of the three task commits
```
Expected: the last 4 commits are the design doc + the 3 implementation tasks (each task commit touches only its listed files). Review the diff for scope: no Linux/Windows changes beyond the two `EVT_MEDIA_CTRL_STAT` lines in Task 1, no `StatusPanel`/`MediaPlayCtrl` changes.

View File

@@ -1,102 +0,0 @@
# Move `wxInspectable` into `DPIAware` — Design Spec
Date: 2026-07-23
Branch: `dev/layout-inspector`
## Overview
Move the `wxInspector::wxInspectable` base class from individual leaf classes (`DPIDialog`, `MainFrame`) into the common `DPIAware<P>` template. This makes every DPIAware widget automatically visible in the inspector tree without requiring each subclass to opt in.
## Motivation
Currently, only `DPIDialog` and `MainFrame` explicitly inherit `wxInspectable`. `DPIFrame` (which `MainFrame` inherits from) does not — `MainFrame` adds it manually. This means:
- Any `DPIAware<T>` widget that isn't `DPIDialog` or `MainFrame` is invisible in the inspector tree
- `DPIFrame` subclasses (`BaseTransparentDPIFrame`, `ImageDPIFrame`, `ModelMallDialog`, `MediaFileFrame`, `SecondaryCheckDialog`, `PrintErrorDialog`, etc.) don't appear
- Adding a new DPIAware widget type requires remembering to also inherit `wxInspectable`
Moving `wxInspectable` to `DPIAware` fixes this for all current and future DPIAware widgets at once.
## Design
### Change 1: `GUI_Utils.hpp` — `DPIAware<P>`
Add `wxInspector::wxInspectable` as a second base class, and call `SetupInspectorAccelerator(this)` in the constructor (after `this->CenterOnParent()`):
```cpp
// Before:
template<class P> class DPIAware : public P
// After:
template<class P> class DPIAware : public P, public wxInspector::wxInspectable
```
Add in the constructor body (after `this->CenterOnParent()` at line 110):
```cpp
SetupInspectorAccelerator(this);
```
This gives every `DPIAware<T>` widget both inspectability and the Ctrl+Shift+I keyboard shortcut automatically. `#include <wx/inspector/inspector.h>` is already present in the file.
### Change 2: `GUI_Utils.hpp` — `DPIDialog`
Remove the now-redundant `wxInspector::wxInspectable` and the `SetupInspectorAccelerator(this)` call:
```cpp
// Before:
class DPIDialog : public DPIAware<wxDialog>, public wxInspector::wxInspectable
// ...
SetupInspectorAccelerator(this);
// After:
class DPIDialog : public DPIAware<wxDialog>
// (SetupInspectorAccelerator call removed — now done in DPIAware constructor)
```
`DPIDialog` gets `wxInspectable` and the accelerator through `DPIAware<wxDialog>` now.
### Change 3: `MainFrame.hpp` — `MainFrame`
Remove the now-redundant `wxInspector::wxInspectable`:
```cpp
// Before:
class MainFrame : public DPIFrame, public wxInspector::wxInspectable
// After:
class MainFrame : public DPIFrame
```
`MainFrame` gets `wxInspectable` through `DPIFrame``DPIAware<wxFrame>`.
### Change 4: `MainFrame.cpp` — `MainFrame` constructor
Remove the now-redundant `SetupInspectorAccelerator(this)` call (line 304). It will be called automatically by the `DPIAware` constructor.
## Impact
| Widget | Before | After |
|--------|--------|-------|
| `DPIDialog` subclasses (~80) | ✓ inspectable | ✓ inspectable (transitive) |
| `MainFrame` | ✓ inspectable | ✓ inspectable (transitive) |
| `DPIFrame` subclasses (8 others) | ✗ invisible | ✓ inspectable |
| Future `DPIAware<T>` | ✗ invisible | ✓ inspectable |
## Files Modified
| File | Change |
|------|--------|
| `src/slic3r/GUI/GUI_Utils.hpp` | `DPIAware<P>` gains `wxInspector::wxInspectable` + `SetupInspectorAccelerator(this)` call; `DPIDialog` drops redundant `wxInspector::wxInspectable` and `SetupInspectorAccelerator(this)` |
| `src/slic3r/GUI/MainFrame.hpp` | `MainFrame` drops redundant `wxInspector::wxInspectable` |
| `src/slic3r/GUI/MainFrame.cpp` | Remove redundant `SetupInspectorAccelerator(this)` from MainFrame constructor |
## Non-Goals
- The `DPIAwarePlugin` detection logic (`dynamic_cast<DPIFrame*>` / `dynamic_cast<DPIDialog*>`) is unchanged
- No new DPI properties — this is purely about tree visibility and accelerator setup
## Risk Assessment
- **Multiple inheritance**: `DPIAware<P>` already has a vtable (virtual destructor). Adding `wxInspectable` adds a second base but no additional data members. The `wxInspector::wxInspectable` class is expected to be a lightweight marker interface.
- **Build**: No new includes needed; `<wx/inspector/inspector.h>` is already included in `GUI_Utils.hpp`.
- **Cross-platform**: The change is standard C++ multiple inheritance — no platform-specific concerns.

View File

@@ -1,244 +0,0 @@
# wxInspector Plugins for OrcaSlicer Custom Controls — Design Spec
Date: 2026-07-23
Branch: `dev/layout-inspector`
## Overview
Create wxInspector plugins that expose OrcaSlicer's custom widget properties in the inspector's property grid. Without these plugins, the inspector shows only generic wxWidgets properties — missing all DPI-awareness data, custom styling, and Orca-specific control state.
## Goals
1. **DPIAware properties** — Inspect and update `scale_factor`, `prev_scale_factor`, `em_unit`, and `normal_font` on any DPIAware-derived widget
2. **Custom widget properties** — Surface Orca-specific properties on `Button`, `CheckBox`, `TextInput`, `SwitchButton`, `ProgressBar`, `Label`, and `LabeledStaticBox`
3. **Minimal source changes** — Only add trivial (one-line) getters/setters to existing classes; no architectural refactoring of Orca's widget hierarchy
## Non-Goals
- Custom inspector panels or AUI tabs (use the existing property grid and method invoker)
- Python-plugin integration (this is C++ wxInspector, not Orca's Python plugin system)
- Event logging customization (the built-in event logger already works)
## Architecture
### Two Plugins
| Plugin | Class | Files |
|--------|-------|-------|
| DPIAware plugin | `DPIAwarePlugin` | `DPIAwarePlugin.hpp`, `DPIAwarePlugin.cpp` |
| Custom widgets plugin | `CustomWidgetsPlugin` | `CustomWidgetsPlugin.hpp`, `CustomWidgetsPlugin.cpp` |
| Registration helper | inline function | `Registration.hpp` |
All files live under `src/slic3r/Utils/wxInspectorPlugins/`.
### Plugin Detection Strategy
**DPIAware plugin**: Uses `dynamic_cast<DPIFrame*>` and `dynamic_cast<DPIDialog*>` as detection gates. `DPIFrame` = `DPIAware<wxFrame>`, `DPIDialog` = `DPIAware<wxDialog>`. Since these are concrete typedefs, `dynamic_cast` works at runtime. This covers `MainFrame`, `SettingsDialog`, and all 8 calibration dialogs (which inherit `DPIDialog`).
**Custom widgets plugin**: Gates broadly on `CLASSINFO(wxWindow)`, then uses per-type `dynamic_cast` inside `GetProperties` to check each Orca-specific type. Only matching types append properties.
### Registration
A single `RegisterOrcaInspectorPlugins()` inline function in `Registration.hpp` creates both plugins as function-local statics (matching the wxInspector built-in provider pattern) and registers them via `wxInspector::RegisterPlugin()`.
Called once from `MainFrame::MainFrame()` after `SetupInspectorAccelerator(this)`.
### Why Separate Plugins?
- DPIAware is a C++ template concept (not a wxClassInfo-isKindOf check), so it needs its own detection logic
- Custom widgets use standard wxClassInfo-based detection, matching the built-in provider pattern
- Two focused files are easier to review and maintain than one monolithic plugin
- Compile-time failure isolation: if a widget header changes, only one plugin breaks
## DPIAware Plugin — Property Specification
### Source Changes (GUI_Utils.hpp)
Four one-liner methods added to the `DPIAware<P>` template class (public section):
```cpp
float scale_factor() const { return m_scale_factor; } // already exists
float prev_scale_factor() const { return m_prev_scale_factor; } // already exists
int em_unit() const { return m_em_unit; } // already exists
void set_scale_factor(float v) { m_scale_factor = v; } // NEW
void set_prev_scale_factor(float v) { m_prev_scale_factor = v; } // NEW
void set_em_unit(int v) { m_em_unit = v; } // NEW
bool force_rescale() const { return m_force_rescale; } // NEW
// m_normal_font getter already exists: normal_font()
```
### Detection
```cpp
bool CanProvideProperties(wxClassInfo* info) override {
// Gated in GetProperties via dynamic_cast on the window itself
return info->IsKindOf(CLASSINFO(wxWindow));
}
```
In `GetProperties`:
```cpp
auto* win = obj.AsWindow();
bool isDPI = dynamic_cast<DPIFrame*>(win) || dynamic_cast<DPIDialog*>(win);
if (!isDPI) return props;
```
### Property Table (category: "DPI Scaling")
| Name | Type | Editable | Getter | Setter |
|------|------|----------|--------|--------|
| Scale Factor | String (float) | Yes | `dpi->scale_factor()` | `dpi->set_scale_factor(v)` |
| Prev Scale Factor | String (float) | Yes | `dpi->prev_scale_factor()` | `dpi->set_prev_scale_factor(v)` |
| EM Unit | Integer | Yes | `dpi->em_unit()` | `dpi->set_em_unit(v)` |
| Normal Font | ReadOnly | No | `dpi->normal_font().GetNativeFontInfoDesc()` | — |
| Force Rescale | Boolean (ReadOnly) | No | `dpi->force_rescale()` | — |
**Note on setters**: The setters simply store values. They do NOT trigger a widget rescale/layout. To see the effect of a changed scale factor, use the inspector's Methods panel to call `Layout()` or resize the window — which triggers the DPI_CHANGED event path naturally.
## Custom Widgets Plugin — Property Specification
All properties are appended to the built-in wxWindow properties. Each widget type is independently detected via `dynamic_cast`.
### Detection gates (in `GetProperties`)
```cpp
auto* win = obj.AsWindow();
if (auto* btn = dynamic_cast<Button*>(win)) { addButtonProperties(btn, props); }
if (auto* cb = dynamic_cast<CheckBox*>(win)) { addCheckBoxProperties(cb, props); }
if (auto* ti = dynamic_cast<TextInput*>(win)) { addTextInputProperties(ti, props); }
if (auto* sb = dynamic_cast<SwitchButton*>(win)) { addSwitchButtonProperties(sb, props); }
if (auto* pb = dynamic_cast<ProgressBar*>(win)) { addProgressBarProperties(pb, props); }
if (auto* lbl = dynamic_cast<Label*>(win)) { addLabelProperties(lbl, props); }
if (auto* lsb = dynamic_cast<LabeledStaticBox*>(win)) { addLabeledStaticBoxProperties(lsb, props); }
```
### Orca Button (`Button`) — category: "Orca Button"
| Name | Type | Editable | Getter | Setter |
|------|------|----------|--------|--------|
| Button Style | Choice | Yes | enum→string | string→enum |
| Button Type | Choice | Yes | enum→string | string→enum |
| Selected | Boolean | Yes | `m_selected` (needs getter) | `SetSelected(v)` |
| Active Icon | ReadOnly | No | icon name string | — |
| Inactive Icon | ReadOnly | No | icon name string | — |
Choices for Button Style: `Regular`, `Confirm`, `Alert`, `Disabled`
Choices for Button Type: `Compact`, `Window`, `Choice`, `Parameter`, `Icon`, `Expanded`
**Source changes needed**: Button's `m_selected` is private. Add one-liner getter:
```cpp
bool IsSelected() const { return m_selected; }
```
### Orca CheckBox (`CheckBox`) — category: "Orca CheckBox"
| Name | Type | Editable | Getter | Setter |
|------|------|----------|--------|--------|
| Half Checked | Boolean | Yes | `m_half_checked` (needs getter) | `SetHalfChecked(v)` |
**Source changes needed**: `m_half_checked` is private. Add one-liner getter:
```cpp
bool IsHalfChecked() const { return m_half_checked; }
```
### Orca TextInput (`TextInput`) — category: "Orca TextInput"
| Name | Type | Editable | Getter | Setter |
|------|------|----------|--------|--------|
| Label | String | Yes | `GetLabel()` (inherited from wxWindow) | `SetLabel(v)` (exists) |
| Text Value | String | Yes | `GetTextCtrl()->GetValue()` (GetTextCtrl is public) | `GetTextCtrl()->SetValue(v)` |
| Corner Radius | Integer | Yes | `GetCornerRadius()` (NEW) | `SetCornerRadius(v)` (exists) |
**Source changes needed**: Add one getter to `TextInput`:
```cpp
int GetCornerRadius() const { return static_cast<int>(radius); }
```
(`radius` is inherited from StaticBox. `SetCornerRadius(double)` already exists. `GetTextCtrl()` is already public.)
### Orca SwitchButton (`SwitchButton`) — category: "Orca SwitchButton"
| Name | Type | Editable | Getter | Setter |
|------|------|----------|--------|--------|
| Value | Boolean | Yes | existing getter | existing setter |
### Orca ProgressBar (`ProgressBar`) — category: "Orca ProgressBar"
| Name | Type | Editable | Getter | Setter |
|------|------|----------|--------|--------|
| Proportion | Float (0-1) | Yes | `pb->m_proportion` (public member) | `pb->m_proportion = v` |
| Show Number | Boolean | Yes | `pb->m_shownumber` (public member) | `pb->m_shownumber = v` |
**No source changes needed**: `m_proportion` and `m_shownumber` are already public members. `SetValue(int)` and `SetProgress(int)` already exist as public methods.
### Orca Label (`Label`) — category: "Orca Label"
| Name | Type | Editable | Getter | Setter |
|------|------|----------|--------|--------|
| Is Hyperlink | Boolean | No | existing flag check | — |
| Font Size | ReadOnly | No | `GetFont().GetPointSize()` | — |
### LabeledStaticBox — category: "LabeledStaticBox"
| Name | Type | Editable | Getter | Setter |
|------|------|----------|--------|--------|
| Corner Radius | Integer | Yes | `GetCornerRadius()` (NEW) | `SetCornerRadius(v)` (exists) |
| Border Width | Integer | Yes | `GetBorderWidth()` (NEW) | `SetBorderWidth(v)` (exists) |
| Border Color | String (hex) | Yes | `GetBorderColor()` (NEW) | `SetBorderColor(v)` (exists) |
| Scale | Float (ReadOnly) | No | `m_scale` (protected, needs getter) | — |
**Source changes needed**: Four one-liner getters added to `LabeledStaticBox`:
```cpp
int GetCornerRadius() const { return m_radius; }
int GetBorderWidth() const { return m_border_width; }
StateColor GetBorderColor() const { return border_color; }
float GetScale() const { return m_scale; }
```
## Files Modified (Existing Code)
| File | Changes |
|------|---------|
| `src/slic3r/GUI/GUI_Utils.hpp` | +4 methods in `DPIAware<P>`: `set_scale_factor()`, `set_prev_scale_factor()`, `set_em_unit()`, `force_rescale()` |
| `src/slic3r/GUI/Widgets/LabeledStaticBox.hpp` | +4 getter declarations: `GetCornerRadius()`, `GetBorderWidth()`, `GetBorderColor()`, `GetScale()` |
| `src/slic3r/GUI/Widgets/LabeledStaticBox.cpp` | +4 getter implementations |
| `src/slic3r/GUI/Widgets/Button.hpp` | +1 getter: `IsSelected()` |
| `src/slic3r/GUI/Widgets/CheckBox.hpp` | +1 getter: `IsHalfChecked()` |
| `src/slic3r/GUI/Widgets/TextInput.hpp` | +1 getter: `GetCornerRadius()` |
| `src/slic3r/GUI/Widgets/ProgressBar.hpp` | None (public members are used directly) |
| `src/slic3r/GUI/MainFrame.cpp` | +1 `#include`, +1 call to `RegisterOrcaInspectorPlugins()` |
| `src/slic3r/CMakeLists.txt` | +4 entries in `SLIC3R_GUI_SOURCES` (the .cpp plugin files) |
## Files Created
```
src/slic3r/Utils/wxInspectorPlugins/
├── DPIAwarePlugin.hpp
├── DPIAwarePlugin.cpp
├── CustomWidgetsPlugin.hpp
├── CustomWidgetsPlugin.cpp
└── Registration.hpp
```
## Build & Linking
The `wxInspector` dependency is already wired:
- `deps/wxInspector/wxInspector.cmake` fetches and builds wxInspector
- `src/CMakeLists.txt` lines 92-93 link `wxInspector::wxInspector` into `wxWidgets_LIBRARIES`
- The plugin files only need `#include <wx/inspector/plugin.h>` and `#include <wx/inspector/inspector.h>` — both available from the installed dependency
No new CMake dependencies needed. Only the new source files need listing in `SLIC3R_GUI_SOURCES`.
## Error Handling & Edge Cases
- **Stale pointers**: Plugin lambdas capture raw pointers, regenerated on every `GetProperties` call (matching wxInspector's built-in provider pattern). Pointers live only until the next tree selection.
- **Widget destruction**: If a widget is destroyed while the inspector is showing its properties, `InspectableObject::IsValid()` returns false and properties are not displayed. The inspector won't show stale data.
- **Invalid property values**: Setters use `sscanf` / `ToLong` with validation (matching built-in patterns). Bogus input is rejected — setter returns `false`, property grid shows error state.
- **DPI drift**: Setting `scale_factor` without triggering rescale means displayed sizes don't match the new factor. This is acceptable — the inspector is a developer tool; operators know to call `Layout()` after making changes.
- **Missing widget type**: If a `dynamic_cast` fails for all types, only built-in wxWindow properties are shown. No crash, no error — just reduced info.
## Future Work (Out of Scope)
- **StateColor visualization**: `StateColor` is a multi-value type (maps bitmask states to colors). A full solution would need a custom property editor (e.g., a table showing each state→color pair). Keep it simple for now.
- **ScalableBitmap display**: Could show the bitmap as an inline thumbnail. Complex property editor work — deferred.
- **More widget types**: `SwitchBoard`, `MultiSwitchButton`, `StepCtrl`, `FanControl`, `DropDown`, `ComboBox`, `AMS*` widgets could all benefit. Add as needed.
- **Property refresh on tree selection**: Currently properties are static snapshots. A "refresh" button or auto-poll could keep values current for rapidly-changing widgets (progress bars, etc.). The built-in wxInspector already provides a tree-refresh button.

View File

@@ -1,110 +0,0 @@
# FFmpeg Media Player for macOS — Design
Date: 2026-08-14
Branch: `dev/ffmpeg-player-macos`
## Problem
The branch's new FFmpeg-based media player (`wxMediaCtrl3` + `AVVideoDecoder`) is used on
Windows and Linux, but macOS still runs the old player: `wxMediaCtrl2.mm`, an ObjC
`BambuPlayer` class dlsym'd from the Bambu network plugin that renders via CALayer.
On macOS, `wxMediaCtrl3` is currently aliased to `wxMediaCtrl2` and FFmpeg is not linked
into the app at all.
Goal: make macOS use the same FFmpeg player as Windows/Linux, linking the **static**
FFmpeg libraries from the deps build instead of dynamic ones.
## Current state (verified)
- New player (Win/Linux): `GUI/wxMediaCtrl3.cpp` + `GUI/AVVideoDecoder.cpp`. Decodes with
FFmpeg (libavcodec/libswscale/libavutil), renders frames into `wxImage` (non-Windows) /
`wxBitmap` (Windows) drawn in a `paintEvent`, feeds via the `Bambu_*` C API
(`BambuTunnel.h`, `BAMBU_DYNAMIC`) dlsym'd from the network plugin through
`StaticBambuLib::get()` (`GUI/Printer/PrinterFileSystem.cpp`, compiled on all platforms).
- Old player (macOS): `GUI/wxMediaCtrl2.mm` uses the ObjC `BambuPlayer` class found via
`dlsym(module, "OBJC_CLASS_$_BambuPlayer")` in `libBambuSource.dylib`.
- The macOS network plugin `libBambuSource.dylib` already exports the full Bambu C API
(verified with `nm`), so the new player needs zero plugin changes.
- FFmpeg linking in `src/slic3r/CMakeLists.txt` is guarded by `if (NOT APPLE)`
macOS currently does not link FFmpeg.
- `deps/FFMPEG/FFMPEG.cmake`: non-MSVC branch builds FFmpeg from source with
`--enable-shared`. The existing arm64 deps build on the dev machine happened to be
configured with both static and shared enabled, so `libavcodec.a` / `libswscale.a` /
`libavutil.a` are already present at
`deps/build/arm64/OrcaSlicer_dep/usr/local/lib/`.
- `EVT_MEDIA_CTRL_STAT` is `wxDEFINE_EVENT`'d in `wxMediaCtrl2.cpp` (Win/Linux) and
`wxMediaCtrl2.mm` (macOS); the define in `wxMediaCtrl3.cpp` is commented out.
- `wxMediaCtrl2` is never instantiated anywhere on any platform — dead code.
- `StatusPanel` already creates `wxMediaCtrl3`; `MediaPlayCtrl` only uses the
`wxMediaCtrl3` interface (`Load/Play/Stop/GetState/GetVideoSize/GetLastError/SetIdleImage`),
so no UI-side changes are needed.
## Approach (approved)
**Reuse the shared player on macOS.** Compile the existing `wxMediaCtrl3.cpp` +
`AVVideoDecoder.cpp` on macOS so all three platforms run one implementation.
Rendering uses the existing `wxImage``DrawBitmap` paint path, identical to Linux.
Known trade-off: frames are scaled to the widget's logical (1x) size, so Retina is
slightly soft compared to the old CALayer player. Accepted for now; a Retina-aware
scaling follow-up is possible later.
Rejected alternative: a native CGImage/CALayer renderer for macOS — faster and
Retina-crisp, but adds a second render implementation to maintain.
## Changes
### 1. Enable the FFmpeg player on macOS (source)
- `GUI/wxMediaCtrl3.h`: remove the `#ifdef __WXMAC__` branch (lines 1822) that aliases
`wxMediaCtrl3``wxMediaCtrl2`. macOS then compiles the real `wxMediaCtrl3` class,
including the `BAMBU_DYNAMIC` BambuTunnel path used on Linux.
- Event symbol fix: move `wxDEFINE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent)` into
`wxMediaCtrl3.cpp` (uncomment the existing line) and remove it from
`wxMediaCtrl2.cpp`. One definition total in the lib; all three platforms resolve it.
### 2. Static FFmpeg linking (deps + app)
- `deps/FFMPEG/FFMPEG.cmake`: in the non-MSVC branch, pass
`--disable-shared --enable-static` when `APPLE`. Linux keeps `--enable-shared`;
Windows keeps its prebuilt shared DLL zips. Fresh macOS deps builds install only
`libavcodec.a` / `libswscale.a` / `libavutil.a` — no dylibs to bundle, no
rpath/install_name handling. (The existing local arm64 deps build already contains
the `.a` files, so no deps rebuild is strictly needed to try the change locally,
but a fresh CI deps build must produce them.)
- `src/slic3r/CMakeLists.txt`:
- APPLE branch of `SLIC3R_GUI_SOURCES`: add `GUI/wxMediaCtrl3.cpp`,
`GUI/wxMediaCtrl3.h`, `GUI/AVVideoDecoder.cpp`, `GUI/AVVideoDecoder.hpp`;
remove `GUI/wxMediaCtrl2.mm` and `GUI/wxMediaCtrl2.h` (the `.h` stays on
disk for the Win/Linux build of `wxMediaCtrl2.cpp`, but nothing on macOS
includes it after this change).
- Add an APPLE mirror of the `NOT APPLE` FFmpeg block: `find_library` for
`libavcodec.a`, `libswscale.a`, `libavutil.a` under `${CMAKE_PREFIX_PATH}/lib`
with `NO_DEFAULT_PATH`, link them (order avcodec → swscale → avutil), and add
`${CMAKE_PREFIX_PATH}/include` as a SYSTEM include directory. Deps are built with
`--disable-zlib` and no external codecs, so the three static libs link cleanly.
### 3. Remove the old player
- Delete `GUI/wxMediaCtrl2.mm` and `GUI/BambuPlayer/BambuPlayer.h` (header used only
by the `.mm`; the real `BambuPlayer` lives inside the network plugin).
- Remove the now-dead `__WXMAC__` section of `GUI/wxMediaCtrl2.h`.
- `wxMediaCtrl2.cpp` (Win/Linux) stays in the build as-is (dead but harmless; out of
scope to remove on this branch).
### 4. Verification
- Build on macOS: `cmake --build build_arm64` (or `build/arm64`).
- Confirm no dynamic FFmpeg dependency: `otool -L` on the app binary shows no `libav*`
dylib references.
- Runtime: with the network plugin loaded, the Device tab camera preview streams via
the FFmpeg player (check the device page / `MediaPlayCtrl`).
- macOS `ctest` still passes — static linking means no test-executable `.so` copying
hacks (unlike the Linux shared-lib setup).
## Out of scope
- Linux (shared libs, AppImage/flatpak bundling) and Windows (prebuilt DLL zips)
keep their current FFmpeg setup.
- Retina-aware frame scaling / native CGImage rendering (follow-up if visual quality
is judged insufficient).
- Audio streaming (neither player plays audio in this UI path).

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12.00,12.00 L12.00,11.96 L12.01,11.92 L12.03,11.89 L12.05,11.85 L12.08,11.82 L12.12,11.80 L12.16,11.78 L12.20,11.76 L12.25,11.75 L12.30,11.75 L12.35,11.75 L12.40,11.77 L12.46,11.79 L12.51,11.81 L12.56,11.85 L12.61,11.89 L12.66,11.94 L12.70,12.00 L12.74,12.06 L12.77,12.14 L12.79,12.21 L12.80,12.29 L12.81,12.38 L12.81,12.47 L12.80,12.56 L12.77,12.65 L12.74,12.74 L12.70,12.83 L12.65,12.92 L12.58,13.01 L12.51,13.09 L12.43,13.17 L12.33,13.24 L12.23,13.30 L12.12,13.36 L12.00,13.40 L11.87,13.43 L11.74,13.46 L11.61,13.46 L11.47,13.46 L11.33,13.45 L11.18,13.41 L11.04,13.37 L10.90,13.31 L10.76,13.24 L10.63,13.15 L10.50,13.05 L10.38,12.93 L10.27,12.81 L10.17,12.67 L10.08,12.51 L10.01,12.35 L9.95,12.18 L9.90,12.00 L9.87,11.81 L9.86,11.62 L9.86,11.43 L9.88,11.23 L9.92,11.03 L9.98,10.83 L10.06,10.64 L10.15,10.45 L10.27,10.27 L10.40,10.09 L10.55,9.93 L10.72,9.78 L10.90,9.64 L11.10,9.52 L11.31,9.41 L11.53,9.32 L11.76,9.25 L12.00,9.20 L12.25,9.17 L12.50,9.17 L12.75,9.18 L13.01,9.22 L13.27,9.29 L13.52,9.37 L13.76,9.48 L14.00,9.62 L14.23,9.77 L14.44,9.95 L14.64,10.15 L14.83,10.37 L15.00,10.60 L15.14,10.86 L15.27,11.12 L15.37,11.41 L15.45,11.70 L15.50,12.00 L15.53,12.31 L15.52,12.62 L15.49,12.94 L15.44,13.25 L15.35,13.56 L15.23,13.87 L15.09,14.16 L14.92,14.45 L14.72,14.72 L14.50,14.98 L14.25,15.22 L13.98,15.44 L13.69,15.63 L13.38,15.80 L13.06,15.94 L12.72,16.06 L12.36,16.15 L12.00,16.20 L11.63,16.22 L11.26,16.21 L10.88,16.17 L10.51,16.09 L10.14,15.98 L9.78,15.84 L9.43,15.66 L9.10,15.46 L8.78,15.22 L8.48,14.95 L8.21,14.65 L7.96,14.33 L7.74,13.99 L7.54,13.62 L7.38,13.24 L7.25,12.84 L7.16,12.42 L7.10,12.00 L7.08,11.57 L7.10,11.14 L7.15,10.70 L7.25,10.27 L7.38,9.85 L7.55,9.43 L7.76,9.03 L8.01,8.65 L8.29,8.29 L8.60,7.95 L8.94,7.64 L9.32,7.35 L9.72,7.10 L10.14,6.88 L10.58,6.70 L11.04,6.56 L11.52,6.46 L12.00,6.40 L12.49,6.38 L12.99,6.41 L13.48,6.48 L13.97,6.59 L14.45,6.75 L14.92,6.95 L15.37,7.19 L15.80,7.47 L16.21,7.79 L16.59,8.15 L16.94,8.54 L17.25,8.97 L17.53,9.42 L17.77,9.90 L17.97,10.40 L18.13,10.92 L18.24,11.45 L18.30,12.00 L18.31,12.55 L18.28,13.11 L18.20,13.66 L18.07,14.21 L17.89,14.74 L17.66,15.27 L17.38,15.77 L17.06,16.25 L16.70,16.70 L16.30,17.12 L15.86,17.51 L15.38,17.86 L14.88,18.17 L14.34,18.43 L13.78,18.65 L13.20,18.82 L12.61,18.93 L12.00,19.00 L11.39,19.01 L10.77,18.97 L10.16,18.87 L9.55,18.72 L8.96,18.52 L8.38,18.26 L7.83,17.96 L7.30,17.60 L6.80,17.20 L6.34,16.75 L5.92,16.26 L5.53,15.73 L5.20,15.17 L4.91,14.58 L4.68,13.96 L4.49,13.32 L4.37,12.67 L4.30,12.00 L4.29,11.33 L4.34,10.65 L4.45,9.98 L4.62,9.31 L4.85,8.66 L5.13,8.03 L5.47,7.43 L5.86,6.85 L6.31,6.31 L6.80,5.80 L7.34,5.34 L7.92,4.93 L8.53,4.56 L9.18,4.25 L9.86,4.00 L10.55,3.80 L11.27,3.67 L12.00,3.60" style="fill:none;stroke:#009688;stroke-linecap:round;stroke-linejoin:round"/><rect x="1.5" y="1.5" width="21" height="21" rx="2" style="fill:none;stroke:#949494;stroke-linecap:round;stroke-linejoin:round"/></svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -0,0 +1,607 @@
{
"bambustudio_commit": "66e405477",
"filaments": {
"OF0UJcb6": {
"bambu_id": "GFG60",
"name": "PolyLite PETG",
"type": "PETG",
"vendor": "Polymaker"
},
"OF0wBGNx": {
"bambu_id": "GFB51",
"name": "Bambu ASA-CF",
"type": "ASA-CF",
"vendor": "Bambu Lab"
},
"OF1UNk9P": {
"bambu_id": "GFP97",
"name": "Generic PP",
"type": "PP",
"vendor": "Generic"
},
"OF2GCW1l": {
"bambu_id": "GFSNL08",
"name": "SUNLU PETG",
"type": "PETG",
"vendor": "SUNLU"
},
"OF2VFe4J": {
"bambu_id": "GFN04",
"name": "Bambu PAHT-CF",
"type": "PA-CF",
"vendor": "Bambu Lab"
},
"OF342jVN": {
"bambu_id": "GFA10",
"name": "Bambu PLA Tough+",
"type": "PLA",
"vendor": "Bambu Lab"
},
"OF4RvVuU": {
"bambu_id": "GFT02",
"name": "Bambu PPS-CF",
"type": "PPS-CF",
"vendor": "Bambu Lab"
},
"OF54B0S0": {
"bambu_id": "GFN06",
"name": "Bambu PPA-CF",
"type": "PPA-CF",
"vendor": "Bambu Lab"
},
"OF5CgdDq": {
"bambu_id": "GFL00",
"name": "PolyLite PLA",
"type": "PLA",
"vendor": "Polymaker"
},
"OF6rdQ6M": {
"bambu_id": "GFT98",
"name": "Generic PPS-CF",
"type": "PPS-CF",
"vendor": "Generic"
},
"OF74KeQR": {
"bambu_id": "GFR98",
"name": "Generic PHA",
"type": "PHA",
"vendor": "Generic"
},
"OF7lOgYF": {
"bambu_id": "GFG96",
"name": "Generic PETG HF",
"type": "PETG",
"vendor": "Generic"
},
"OF8Tlg47": {
"bambu_id": "GFN96",
"name": "Generic PPA-GF",
"type": "PPA-GF",
"vendor": "Generic"
},
"OF8tPByX": {
"bambu_id": "GFN97",
"name": "Generic PPA-CF",
"type": "PPA-CF",
"vendor": "Generic"
},
"OF9OlTWH": {
"bambu_id": "GFA07",
"name": "Bambu PLA Marble",
"type": "PLA",
"vendor": "Bambu Lab"
},
"OFAnyRUI": {
"bambu_id": "GFS02",
"name": "Bambu Support For PLA",
"type": "PLA",
"vendor": "Bambu Lab"
},
"OFBSW57R": {
"bambu_id": "GFA11",
"name": "Bambu PLA Aero",
"type": "PLA-AERO",
"vendor": "Bambu Lab"
},
"OFBw6eEG": {
"bambu_id": "GFL05",
"name": "Overture Matte PLA",
"type": "PLA",
"vendor": "Overture"
},
"OFCD8qiU": {
"bambu_id": "GFR99",
"name": "Generic EVA",
"type": "EVA",
"vendor": "Generic"
},
"OFDGigEI": {
"bambu_id": "GFA13",
"name": "Bambu PLA Dynamic",
"type": "PLA",
"vendor": "Bambu Lab"
},
"OFDSrzZ8": {
"bambu_id": "GFL99",
"name": "Generic PLA",
"type": "PLA",
"vendor": "Generic"
},
"OFDvXujf": {
"bambu_id": "GFS99",
"name": "Generic PVA",
"type": "PVA",
"vendor": "Generic"
},
"OFDxfPgH": {
"bambu_id": "GFA08",
"name": "Bambu PLA Sparkle",
"type": "PLA",
"vendor": "Bambu Lab"
},
"OFEGNJD4": {
"bambu_id": "GFA05",
"name": "Bambu PLA Silk",
"type": "PLA",
"vendor": "Bambu Lab"
},
"OFEkPBwx": {
"bambu_id": "GFA12",
"name": "Bambu PLA Glow",
"type": "PLA",
"vendor": "Bambu Lab"
},
"OFEswT5W": {
"bambu_id": "GFA50",
"name": "Bambu PLA-CF",
"type": "PLA-CF",
"vendor": "Bambu Lab"
},
"OFFNYwWR": {
"bambu_id": "GFN03",
"name": "Bambu PA-CF",
"type": "PA-CF",
"vendor": "Bambu Lab"
},
"OFFbSnCD": {
"bambu_id": "GFA17",
"name": "Bambu PLA Translucent",
"type": "PLA",
"vendor": "Bambu Lab"
},
"OFFvzqcd": {
"bambu_id": "GFG00",
"name": "Bambu PETG Basic",
"type": "PETG",
"vendor": "Bambu Lab"
},
"OFHWSM21": {
"bambu_id": "GFL54",
"name": "Fiberon PET-CF",
"type": "PET-CF",
"vendor": "Polymaker"
},
"OFHa48An": {
"bambu_id": "GFT01",
"name": "Bambu PET-CF",
"type": "PET-CF",
"vendor": "Bambu Lab"
},
"OFHmPYRy": {
"bambu_id": "GFSNL04",
"name": "SUNLU PLA+ 2.0",
"type": "PLA",
"vendor": "SUNLU"
},
"OFIBbYO5": {
"bambu_id": "GFU02",
"name": "Bambu TPU for AMS",
"type": "TPU-AMS",
"vendor": "Bambu Lab"
},
"OFIfnzxC": {
"bambu_id": "GFS05",
"name": "Bambu Support For PLA/PETG",
"type": "PLA",
"vendor": "Bambu Lab"
},
"OFKhMPeX": {
"bambu_id": "GFC00",
"name": "Bambu PC",
"type": "PC",
"vendor": "Bambu Lab"
},
"OFLJ8S6I": {
"bambu_id": "GFSNL07",
"name": "SUNLU Wood PLA",
"type": "PLA",
"vendor": "SUNLU"
},
"OFLPAxz3": {
"bambu_id": "GFB98",
"name": "Generic ASA",
"type": "ASA",
"vendor": "Generic"
},
"OFLakOUI": {
"bambu_id": "GFC99",
"name": "Generic PC",
"type": "PC",
"vendor": "Generic"
},
"OFMTK0UC": {
"bambu_id": "GFS03",
"name": "Bambu Support For PA/PET",
"type": "PA",
"vendor": "Bambu Lab"
},
"OFMUWNkp": {
"bambu_id": "GFSNL03",
"name": "SUNLU PLA+",
"type": "PLA",
"vendor": "SUNLU"
},
"OFMjtqTC": {
"bambu_id": "GFA16",
"name": "Bambu PLA Wood",
"type": "PLA",
"vendor": "Bambu Lab"
},
"OFNk8bxk": {
"bambu_id": "GFN08",
"name": "Bambu PA6-GF",
"type": "PA-GF",
"vendor": "Bambu Lab"
},
"OFOvv91M": {
"bambu_id": "GFB60",
"name": "PolyLite ABS",
"type": "ABS",
"vendor": "Polymaker"
},
"OFPklMI1": {
"bambu_id": "GFP99",
"name": "Generic PE",
"type": "PE",
"vendor": "Generic"
},
"OFQ3e56w": {
"bambu_id": "GFA15",
"name": "Bambu PLA Galaxy",
"type": "PLA",
"vendor": "Bambu Lab"
},
"OFQHiNJs": {
"bambu_id": "GFS01",
"name": "Bambu Support G",
"type": "PA",
"vendor": "Bambu Lab"
},
"OFQLcbps": {
"bambu_id": "GFN98",
"name": "Generic PA-CF",
"type": "PA-CF",
"vendor": "Generic"
},
"OFS2tn6G": {
"bambu_id": "GFL53",
"name": "Fiberon PA612-CF",
"type": "PA",
"vendor": "Polymaker"
},
"OFTHDCqA": {
"bambu_id": "GFA19",
"name": "Bambu PLA Pure",
"type": "PLA",
"vendor": "Bambu Lab"
},
"OFTRZ8Y4": {
"bambu_id": "GFG50",
"name": "Bambu PETG-CF",
"type": "PETG-CF",
"vendor": "Bambu Lab"
},
"OFUanySo": {
"bambu_id": "GFA06",
"name": "Bambu PLA Silk+",
"type": "PLA",
"vendor": "Bambu Lab"
},
"OFVCkX5w": {
"bambu_id": "GFU01",
"name": "Bambu TPU 95A",
"type": "TPU",
"vendor": "Bambu Lab"
},
"OFW29a9R": {
"bambu_id": "GFL01",
"name": "PolyTerra PLA",
"type": "PLA",
"vendor": "Polymaker"
},
"OFWbdGsC": {
"bambu_id": "GFL98",
"name": "Generic PLA-CF",
"type": "PLA-CF",
"vendor": "Generic"
},
"OFX0ycRQ": {
"bambu_id": "GFL52",
"name": "Fiberon PA12-CF",
"type": "PA-CF",
"vendor": "Polymaker"
},
"OFXIbw5D": {
"bambu_id": "GFA01",
"name": "Bambu PLA Matte",
"type": "PLA",
"vendor": "Bambu Lab"
},
"OFXkm8q1": {
"bambu_id": "GFP96",
"name": "Generic PP-CF",
"type": "PP-CF",
"vendor": "Generic"
},
"OFXzQ4yL": {
"bambu_id": "GFB02",
"name": "Bambu ASA-Aero",
"type": "ASA-AERO",
"vendor": "Bambu Lab"
},
"OFY9muEs": {
"bambu_id": "GFB99",
"name": "Generic ABS",
"type": "ABS",
"vendor": "Generic"
},
"OFYPdQJh": {
"bambu_id": "GFG99",
"name": "Generic PETG",
"type": "PETG",
"vendor": "Generic"
},
"OFaQMgRH": {
"bambu_id": "GFA09",
"name": "Bambu PLA Tough",
"type": "PLA",
"vendor": "Bambu Lab"
},
"OFc3xdm9": {
"bambu_id": "GFL04",
"name": "Overture PLA",
"type": "PLA",
"vendor": "Overture"
},
"OFcytyoA": {
"bambu_id": "GFL06",
"name": "Fiberon PETG-ESD",
"type": "PETG",
"vendor": "Polymaker"
},
"OFd0Fv0k": {
"bambu_id": "GFP98",
"name": "Generic PE-CF",
"type": "PE-CF",
"vendor": "Generic"
},
"OFdyfQvU": {
"bambu_id": "GFG03",
"name": "Bambu PETG Matte",
"type": "PETG",
"vendor": "Bambu Lab"
},
"OFesA6rF": {
"bambu_id": "GFL96",
"name": "Generic PLA Silk",
"type": "PLA",
"vendor": "Generic"
},
"OFf6mfQO": {
"bambu_id": "GFS06",
"name": "Bambu Support for ABS",
"type": "ABS",
"vendor": "Bambu Lab"
},
"OFfBpSRI": {
"bambu_id": "GFB01",
"name": "Bambu ASA",
"type": "ASA",
"vendor": "Bambu Lab"
},
"OFg57Nmc": {
"bambu_id": "GFC01",
"name": "Bambu PC FR",
"type": "PC",
"vendor": "Bambu Lab"
},
"OFg8ndtj": {
"bambu_id": "GFN99",
"name": "Generic PA",
"type": "PA",
"vendor": "Generic"
},
"OFgbpcy9": {
"bambu_id": "GFU99",
"name": "Generic TPU",
"type": "TPU",
"vendor": "Generic"
},
"OFhuaUQB": {
"bambu_id": "GFB00",
"name": "Bambu ABS",
"type": "ABS",
"vendor": "Bambu Lab"
},
"OFk8t9mz": {
"bambu_id": "GFL55",
"name": "Fiberon PETG-rCF",
"type": "PETG-CF",
"vendor": "Polymaker"
},
"OFkOviHk": {
"bambu_id": "GFL50",
"name": "Fiberon PA6-CF",
"type": "PA6-CF",
"vendor": "Polymaker"
},
"OFknl9Iz": {
"bambu_id": "GFB50",
"name": "Bambu ABS-GF",
"type": "ABS-GF",
"vendor": "Bambu Lab"
},
"OFlfuj2k": {
"bambu_id": "GFU04",
"name": "Bambu TPU 85A",
"type": "TPU",
"vendor": "Bambu Lab"
},
"OFmN2lvw": {
"bambu_id": "GFU98",
"name": "Generic TPU for AMS",
"type": "TPU-AMS",
"vendor": "Generic"
},
"OFmpMwxS": {
"bambu_id": "GFL95",
"name": "Generic PLA High Speed",
"type": "PLA",
"vendor": "Generic"
},
"OFnfxTvi": {
"bambu_id": "GFA18",
"name": "Bambu PLA Lite",
"type": "PLA",
"vendor": "Bambu Lab"
},
"OFniMuTN": {
"bambu_id": "GFN05",
"name": "Bambu PA6-CF",
"type": "PA6-CF",
"vendor": "Bambu Lab"
},
"OFo2UF2C": {
"bambu_id": "GFS97",
"name": "Generic BVOH",
"type": "BVOH",
"vendor": "Generic"
},
"OFoYSJKi": {
"bambu_id": "GFG98",
"name": "Generic PETG-CF",
"type": "PETG-CF",
"vendor": "Generic"
},
"OFoiVqVM": {
"bambu_id": "GFA00",
"name": "Bambu PLA Basic",
"type": "PLA",
"vendor": "Bambu Lab"
},
"OFovEIbw": {
"bambu_id": "GFG02",
"name": "Bambu PETG HF",
"type": "PETG",
"vendor": "Bambu Lab"
},
"OFpPGSKG": {
"bambu_id": "GFSNL05",
"name": "SUNLU Silk PLA+",
"type": "PLA",
"vendor": "SUNLU"
},
"OFpW4gdi": {
"bambu_id": "GFSNL02",
"name": "SUNLU PLA Matte",
"type": "PLA",
"vendor": "SUNLU"
},
"OFq9svOz": {
"bambu_id": "GFT97",
"name": "Generic PPS",
"type": "PPS",
"vendor": "Generic"
},
"OFqINlYj": {
"bambu_id": "GFL03",
"name": "eSUN PLA+",
"type": "PLA",
"vendor": "eSUN"
},
"OFrKLeE3": {
"bambu_id": "GFA02",
"name": "Bambu PLA Metal",
"type": "PLA",
"vendor": "Bambu Lab"
},
"OFsFon5l": {
"bambu_id": "GFS98",
"name": "Generic HIPS",
"type": "HIPS",
"vendor": "Generic"
},
"OFsHSVZc": {
"bambu_id": "GFS00",
"name": "Bambu Support W",
"type": "PLA",
"vendor": "Bambu Lab"
},
"OFsijjtH": {
"bambu_id": "GFP95",
"name": "Generic PP-GF",
"type": "PP-GF",
"vendor": "Generic"
},
"OFtkLO6q": {
"bambu_id": "GFU03",
"name": "Bambu TPU 90A",
"type": "TPU",
"vendor": "Bambu Lab"
},
"OFu1evlr": {
"bambu_id": "GFG97",
"name": "Generic PCTG",
"type": "PCTG",
"vendor": "Generic"
},
"OFvKUnLh": {
"bambu_id": "GFU00",
"name": "Bambu TPU 95A HF",
"type": "TPU",
"vendor": "Bambu Lab"
},
"OFvrXuV7": {
"bambu_id": "GFB61",
"name": "PolyLite ASA",
"type": "ASA",
"vendor": "Polymaker"
},
"OFwPrlCM": {
"bambu_id": "GFG01",
"name": "Bambu PETG Translucent",
"type": "PETG",
"vendor": "Bambu Lab"
},
"OFwaYjL6": {
"bambu_id": "GFL51",
"name": "Fiberon PA6-GF",
"type": "PA-GF",
"vendor": "Polymaker"
},
"OFxUwUeW": {
"bambu_id": "GFSNL06",
"name": "SUNLU PLA Marble",
"type": "PLA",
"vendor": "SUNLU"
},
"OFzyIxba": {
"bambu_id": "GFS04",
"name": "Bambu PVA",
"type": "PVA",
"vendor": "Bambu Lab"
}
},
"generated": "2026-09-04",
"source": "https://github.com/bambulab/BambuStudio"
}

View File

@@ -1,6 +1,6 @@
{ {
"name": "Afinia", "name": "Afinia",
"version": "02.04.00.02", "version": "02.04.00.03",
"force_update": "0", "force_update": "0",
"description": "Afinia configurations", "description": "Afinia configurations",
"machine_model_list": [ "machine_model_list": [

View File

@@ -1,6 +1,6 @@
{ {
"type": "filament", "type": "filament",
"filament_id": "GFB00_01", "filament_id": "OFLfywkp",
"setting_id": "wAJTMxtCY7EoavRi", "setting_id": "wAJTMxtCY7EoavRi",
"name": "Afinia ABS+@HS", "name": "Afinia ABS+@HS",
"from": "system", "from": "system",

View File

@@ -1,6 +1,6 @@
{ {
"type": "filament", "type": "filament",
"filament_id": "GFB00_01", "filament_id": "OFV5wEMe",
"setting_id": "qCDnb2iBaz4hd4vX", "setting_id": "qCDnb2iBaz4hd4vX",
"name": "Afinia ABS@HS", "name": "Afinia ABS@HS",
"from": "system", "from": "system",

View File

@@ -1,6 +1,6 @@
{ {
"type": "filament", "type": "filament",
"filament_id": "GFA00_01", "filament_id": "OF9HCdyQ",
"setting_id": "N3sCgjdjvp6FTtw9", "setting_id": "N3sCgjdjvp6FTtw9",
"name": "Afinia PLA@HS", "name": "Afinia PLA@HS",
"from": "system", "from": "system",

View File

@@ -4,7 +4,7 @@
"inherits": "fdm_filament_tpu", "inherits": "fdm_filament_tpu",
"from": "system", "from": "system",
"setting_id": "zUqTgAEbqTN1EdRl", "setting_id": "zUqTgAEbqTN1EdRl",
"filament_id": "GFU01_01", "filament_id": "OFDJU6R3",
"instantiation": "true", "instantiation": "true",
"filament_vendor": [ "filament_vendor": [
"Afinia" "Afinia"

View File

@@ -1,6 +1,6 @@
{ {
"type": "filament", "type": "filament",
"filament_id": "GFB00_01", "filament_id": "OFXi59OX",
"setting_id": "OxIiEYjbhEvSykaQ", "setting_id": "OxIiEYjbhEvSykaQ",
"name": "Afinia Value ABS@HS", "name": "Afinia Value ABS@HS",
"from": "system", "from": "system",

View File

@@ -1,6 +1,6 @@
{ {
"type": "filament", "type": "filament",
"filament_id": "GFA00_01", "filament_id": "OFgHh8ly",
"setting_id": "BASsUdyvElEVJ9AA", "setting_id": "BASsUdyvElEVJ9AA",
"name": "Afinia Value PLA@HS", "name": "Afinia Value PLA@HS",
"from": "system", "from": "system",

View File

@@ -1,6 +1,6 @@
{ {
"name": "Anker", "name": "Anker",
"version": "02.04.00.01", "version": "02.04.00.02",
"force_update": "0", "force_update": "0",
"description": "Anker configurations", "description": "Anker configurations",
"machine_model_list": [ "machine_model_list": [
@@ -161,172 +161,172 @@
"sub_path": "filament/fdm_filament_tpu.json" "sub_path": "filament/fdm_filament_tpu.json"
}, },
{ {
"name": "Anker Generic ABS @base", "name": "Generic ABS @Anker base",
"sub_path": "filament/Anker Generic ABS @base.json" "sub_path": "filament/Generic ABS @Anker base.json"
}, },
{ {
"name": "Anker Generic ASA @base", "name": "Generic ASA @Anker base",
"sub_path": "filament/Anker Generic ASA @base.json" "sub_path": "filament/Generic ASA @Anker base.json"
}, },
{ {
"name": "Anker Generic PA @base", "name": "Generic PA @Anker base",
"sub_path": "filament/Anker Generic PA @base.json" "sub_path": "filament/Generic PA @Anker base.json"
}, },
{ {
"name": "Anker Generic PA-CF @base", "name": "Generic PA-CF @Anker base",
"sub_path": "filament/Anker Generic PA-CF @base.json" "sub_path": "filament/Generic PA-CF @Anker base.json"
}, },
{ {
"name": "Anker Generic PC @base", "name": "Generic PC @Anker base",
"sub_path": "filament/Anker Generic PC @base.json" "sub_path": "filament/Generic PC @Anker base.json"
}, },
{ {
"name": "Anker Generic PETG @base", "name": "Generic PETG @Anker base",
"sub_path": "filament/Anker Generic PETG @base.json" "sub_path": "filament/Generic PETG @Anker base.json"
}, },
{ {
"name": "Anker Generic PETG-CF @base", "name": "Generic PETG-CF @Anker base",
"sub_path": "filament/Anker Generic PETG-CF @base.json" "sub_path": "filament/Generic PETG-CF @Anker base.json"
}, },
{ {
"name": "Anker Generic PLA @base", "name": "Generic PLA @Anker base",
"sub_path": "filament/Anker Generic PLA @base.json" "sub_path": "filament/Generic PLA @Anker base.json"
}, },
{ {
"name": "Anker Generic PLA Silk @base", "name": "Generic PLA Silk @Anker base",
"sub_path": "filament/Anker Generic PLA Silk @base.json" "sub_path": "filament/Generic PLA Silk @Anker base.json"
}, },
{ {
"name": "Anker Generic PLA+ @base", "name": "Generic PLA+ @Anker base",
"sub_path": "filament/Anker Generic PLA+ @base.json" "sub_path": "filament/Generic PLA+ @Anker base.json"
}, },
{ {
"name": "Anker Generic PLA-CF @base", "name": "Generic PLA-CF @Anker base",
"sub_path": "filament/Anker Generic PLA-CF @base.json" "sub_path": "filament/Generic PLA-CF @Anker base.json"
}, },
{ {
"name": "Anker Generic PVA @base", "name": "Generic PVA @Anker base",
"sub_path": "filament/Anker Generic PVA @base.json" "sub_path": "filament/Generic PVA @Anker base.json"
}, },
{ {
"name": "Anker Generic TPU @base", "name": "Generic TPU @Anker base",
"sub_path": "filament/Anker Generic TPU @base.json" "sub_path": "filament/Generic TPU @Anker base.json"
}, },
{ {
"name": "Anker Generic ABS", "name": "Generic ABS @Anker",
"sub_path": "filament/Anker Generic ABS.json" "sub_path": "filament/Generic ABS @Anker.json"
}, },
{ {
"name": "Anker Generic ABS 0.2 nozzle", "name": "Generic ABS @Anker 0.2 nozzle",
"sub_path": "filament/Anker Generic ABS 0.2 nozzle.json" "sub_path": "filament/Generic ABS @Anker 0.2 nozzle.json"
}, },
{ {
"name": "Anker Generic ABS 0.25 nozzle", "name": "Generic ABS @Anker 0.25 nozzle",
"sub_path": "filament/Anker Generic ABS 0.25 nozzle.json" "sub_path": "filament/Generic ABS @Anker 0.25 nozzle.json"
}, },
{ {
"name": "Anker Generic ASA", "name": "Generic ASA @Anker",
"sub_path": "filament/Anker Generic ASA.json" "sub_path": "filament/Generic ASA @Anker.json"
}, },
{ {
"name": "Anker Generic ASA 0.2 nozzle", "name": "Generic ASA @Anker 0.2 nozzle",
"sub_path": "filament/Anker Generic ASA 0.2 nozzle.json" "sub_path": "filament/Generic ASA @Anker 0.2 nozzle.json"
}, },
{ {
"name": "Anker Generic ASA 0.25 nozzle", "name": "Generic ASA @Anker 0.25 nozzle",
"sub_path": "filament/Anker Generic ASA 0.25 nozzle.json" "sub_path": "filament/Generic ASA @Anker 0.25 nozzle.json"
}, },
{ {
"name": "Anker Generic PA", "name": "Generic PA @Anker",
"sub_path": "filament/Anker Generic PA.json" "sub_path": "filament/Generic PA @Anker.json"
}, },
{ {
"name": "Anker Generic PA 0.2 nozzle", "name": "Generic PA @Anker 0.2 nozzle",
"sub_path": "filament/Anker Generic PA 0.2 nozzle.json" "sub_path": "filament/Generic PA @Anker 0.2 nozzle.json"
}, },
{ {
"name": "Anker Generic PA 0.25 nozzle", "name": "Generic PA @Anker 0.25 nozzle",
"sub_path": "filament/Anker Generic PA 0.25 nozzle.json" "sub_path": "filament/Generic PA @Anker 0.25 nozzle.json"
}, },
{ {
"name": "Anker Generic PA-CF", "name": "Generic PA-CF @Anker",
"sub_path": "filament/Anker Generic PA-CF.json" "sub_path": "filament/Generic PA-CF @Anker.json"
}, },
{ {
"name": "Anker Generic PC", "name": "Generic PC @Anker",
"sub_path": "filament/Anker Generic PC.json" "sub_path": "filament/Generic PC @Anker.json"
}, },
{ {
"name": "Anker Generic PC 0.2 nozzle", "name": "Generic PC @Anker 0.2 nozzle",
"sub_path": "filament/Anker Generic PC 0.2 nozzle.json" "sub_path": "filament/Generic PC @Anker 0.2 nozzle.json"
}, },
{ {
"name": "Anker Generic PC 0.25 nozzle", "name": "Generic PC @Anker 0.25 nozzle",
"sub_path": "filament/Anker Generic PC 0.25 nozzle.json" "sub_path": "filament/Generic PC @Anker 0.25 nozzle.json"
}, },
{ {
"name": "Anker Generic PETG", "name": "Generic PETG @Anker",
"sub_path": "filament/Anker Generic PETG.json" "sub_path": "filament/Generic PETG @Anker.json"
}, },
{ {
"name": "Anker Generic PETG 0.2 nozzle", "name": "Generic PETG @Anker 0.2 nozzle",
"sub_path": "filament/Anker Generic PETG 0.2 nozzle.json" "sub_path": "filament/Generic PETG @Anker 0.2 nozzle.json"
}, },
{ {
"name": "Anker Generic PETG 0.25 nozzle", "name": "Generic PETG @Anker 0.25 nozzle",
"sub_path": "filament/Anker Generic PETG 0.25 nozzle.json" "sub_path": "filament/Generic PETG @Anker 0.25 nozzle.json"
}, },
{ {
"name": "Anker Generic PETG-CF", "name": "Generic PETG-CF @Anker",
"sub_path": "filament/Anker Generic PETG-CF.json" "sub_path": "filament/Generic PETG-CF @Anker.json"
}, },
{ {
"name": "Anker Generic PLA", "name": "Generic PLA @Anker",
"sub_path": "filament/Anker Generic PLA.json" "sub_path": "filament/Generic PLA @Anker.json"
}, },
{ {
"name": "Anker Generic PLA 0.2 nozzle", "name": "Generic PLA @Anker 0.2 nozzle",
"sub_path": "filament/Anker Generic PLA 0.2 nozzle.json" "sub_path": "filament/Generic PLA @Anker 0.2 nozzle.json"
}, },
{ {
"name": "Anker Generic PLA 0.25 nozzle", "name": "Generic PLA @Anker 0.25 nozzle",
"sub_path": "filament/Anker Generic PLA 0.25 nozzle.json" "sub_path": "filament/Generic PLA @Anker 0.25 nozzle.json"
}, },
{ {
"name": "Anker Generic PLA Silk", "name": "Generic PLA Silk @Anker",
"sub_path": "filament/Anker Generic PLA Silk.json" "sub_path": "filament/Generic PLA Silk @Anker.json"
}, },
{ {
"name": "Anker Generic PLA Silk 0.2 nozzle", "name": "Generic PLA Silk @Anker 0.2 nozzle",
"sub_path": "filament/Anker Generic PLA Silk 0.2 nozzle.json" "sub_path": "filament/Generic PLA Silk @Anker 0.2 nozzle.json"
}, },
{ {
"name": "Anker Generic PLA Silk 0.25 nozzle", "name": "Generic PLA Silk @Anker 0.25 nozzle",
"sub_path": "filament/Anker Generic PLA Silk 0.25 nozzle.json" "sub_path": "filament/Generic PLA Silk @Anker 0.25 nozzle.json"
}, },
{ {
"name": "Anker Generic PLA+", "name": "Generic PLA+ @Anker",
"sub_path": "filament/Anker Generic PLA+.json" "sub_path": "filament/Generic PLA+ @Anker.json"
}, },
{ {
"name": "Anker Generic PLA+ 0.2 nozzle", "name": "Generic PLA+ @Anker 0.2 nozzle",
"sub_path": "filament/Anker Generic PLA+ 0.2 nozzle.json" "sub_path": "filament/Generic PLA+ @Anker 0.2 nozzle.json"
}, },
{ {
"name": "Anker Generic PLA+ 0.25 nozzle", "name": "Generic PLA+ @Anker 0.25 nozzle",
"sub_path": "filament/Anker Generic PLA+ 0.25 nozzle.json" "sub_path": "filament/Generic PLA+ @Anker 0.25 nozzle.json"
}, },
{ {
"name": "Anker Generic PLA-CF", "name": "Generic PLA-CF @Anker",
"sub_path": "filament/Anker Generic PLA-CF.json" "sub_path": "filament/Generic PLA-CF @Anker.json"
}, },
{ {
"name": "Anker Generic PVA", "name": "Generic PVA @Anker",
"sub_path": "filament/Anker Generic PVA.json" "sub_path": "filament/Generic PVA @Anker.json"
}, },
{ {
"name": "Anker Generic TPU", "name": "Generic TPU @Anker",
"sub_path": "filament/Anker Generic TPU.json" "sub_path": "filament/Generic TPU @Anker.json"
} }
], ],
"machine_list": [ "machine_list": [

View File

@@ -1,16 +0,0 @@
{
"type": "filament",
"name": "Anker Generic PLA Silk 0.2 nozzle",
"inherits": "Anker Generic PLA Silk @base",
"from": "system",
"setting_id": "A1l6NiwRrasdV556",
"instantiation": "true",
"filament_max_volumetric_speed": [
"2"
],
"compatible_printers": [
"Anker M5 0.2 nozzle",
"Anker M5 All-Metal 0.2 nozzle",
"Anker M5C 0.2 nozzle"
]
}

View File

@@ -1,16 +0,0 @@
{
"type": "filament",
"name": "Anker Generic PLA Silk 0.25 nozzle",
"inherits": "Anker Generic PLA Silk @base",
"from": "system",
"setting_id": "yzHmKTOtA9JamlNf",
"instantiation": "true",
"filament_max_volumetric_speed": [
"3"
],
"compatible_printers": [
"Anker M5 0.25 nozzle",
"Anker M5 All-Metal 0.25 nozzle",
"Anker M5C 0.25 nozzle"
]
}

View File

@@ -1,16 +0,0 @@
{
"type": "filament",
"name": "Anker Generic PLA Silk",
"inherits": "Anker Generic PLA Silk @base",
"from": "system",
"setting_id": "BGttYO9m2rGcnrEG",
"instantiation": "true",
"compatible_printers": [
"Anker M5 0.4 nozzle",
"Anker M5 0.6 nozzle",
"Anker M5 All-Metal 0.4 nozzle",
"Anker M5 All-Metal 0.6 nozzle",
"Anker M5C 0.4 nozzle",
"Anker M5C 0.6 nozzle"
]
}

View File

@@ -1,16 +0,0 @@
{
"type": "filament",
"name": "Anker Generic PLA+ 0.2 nozzle",
"inherits": "Anker Generic PLA+ @base",
"from": "system",
"setting_id": "6IcMSjyxt0szdUuY",
"instantiation": "true",
"filament_max_volumetric_speed": [
"2"
],
"compatible_printers": [
"Anker M5 0.2 nozzle",
"Anker M5 All-Metal 0.2 nozzle",
"Anker M5C 0.2 nozzle"
]
}

View File

@@ -1,16 +0,0 @@
{
"type": "filament",
"name": "Anker Generic PLA+ 0.25 nozzle",
"inherits": "Anker Generic PLA+ @base",
"from": "system",
"setting_id": "a2Rf07ZUhpTPONN1",
"instantiation": "true",
"filament_max_volumetric_speed": [
"3"
],
"compatible_printers": [
"Anker M5 0.25 nozzle",
"Anker M5 All-Metal 0.25 nozzle",
"Anker M5C 0.25 nozzle"
]
}

View File

@@ -1,16 +0,0 @@
{
"type": "filament",
"name": "Anker Generic PLA+",
"inherits": "Anker Generic PLA+ @base",
"from": "system",
"setting_id": "0yQN44WNvLVjQu2b",
"instantiation": "true",
"compatible_printers": [
"Anker M5 0.4 nozzle",
"Anker M5 0.6 nozzle",
"Anker M5 All-Metal 0.4 nozzle",
"Anker M5 All-Metal 0.6 nozzle",
"Anker M5C 0.4 nozzle",
"Anker M5C 0.6 nozzle"
]
}

View File

@@ -1,16 +0,0 @@
{
"type": "filament",
"name": "Anker Generic PLA-CF",
"inherits": "Anker Generic PLA-CF @base",
"from": "system",
"setting_id": "diNUVM7UcHLnOr9J",
"instantiation": "true",
"compatible_printers": [
"Anker M5 0.4 nozzle",
"Anker M5 0.6 nozzle",
"Anker M5 All-Metal 0.4 nozzle",
"Anker M5 All-Metal 0.6 nozzle",
"Anker M5C 0.4 nozzle",
"Anker M5C 0.6 nozzle"
]
}

View File

@@ -1,16 +0,0 @@
{
"type": "filament",
"name": "Anker Generic PLA",
"inherits": "Anker Generic PLA @base",
"from": "system",
"setting_id": "qfKC91VAAFZSExhm",
"instantiation": "true",
"compatible_printers": [
"Anker M5 0.4 nozzle",
"Anker M5 0.6 nozzle",
"Anker M5 All-Metal 0.4 nozzle",
"Anker M5 All-Metal 0.6 nozzle",
"Anker M5C 0.4 nozzle",
"Anker M5C 0.6 nozzle"
]
}

View File

@@ -1,16 +0,0 @@
{
"type": "filament",
"name": "Anker Generic PVA",
"inherits": "Anker Generic PVA @base",
"from": "system",
"setting_id": "GRtdOKUkQfZ5eDH4",
"instantiation": "true",
"compatible_printers": [
"Anker M5 0.4 nozzle",
"Anker M5 0.6 nozzle",
"Anker M5 All-Metal 0.4 nozzle",
"Anker M5 All-Metal 0.6 nozzle",
"Anker M5C 0.4 nozzle",
"Anker M5C 0.6 nozzle"
]
}

View File

@@ -1,16 +0,0 @@
{
"type": "filament",
"name": "Anker Generic TPU",
"inherits": "Anker Generic TPU @base",
"from": "system",
"setting_id": "YyTaPGGiEyAzmh9A",
"instantiation": "true",
"compatible_printers": [
"Anker M5 0.4 nozzle",
"Anker M5 0.6 nozzle",
"Anker M5 All-Metal 0.4 nozzle",
"Anker M5 All-Metal 0.6 nozzle",
"Anker M5C 0.4 nozzle",
"Anker M5C 0.6 nozzle"
]
}

View File

@@ -1,9 +1,10 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic ABS 0.2 nozzle", "name": "Generic ABS @Anker 0.2 nozzle",
"inherits": "Anker Generic ABS @base", "inherits": "Generic ABS @Anker base",
"renamed_from": "Anker Generic ABS 0.2 nozzle",
"from": "system", "from": "system",
"setting_id": "BD5ODYVM90Ig44C5", "setting_id": "iOCt7x95XbWYMe5q",
"instantiation": "true", "instantiation": "true",
"filament_max_volumetric_speed": [ "filament_max_volumetric_speed": [
"2" "2"

View File

@@ -1,9 +1,10 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PETG 0.25 nozzle", "name": "Generic ABS @Anker 0.25 nozzle",
"inherits": "Anker Generic PETG @base", "inherits": "Generic ABS @Anker base",
"renamed_from": "Anker Generic ABS 0.25 nozzle",
"from": "system", "from": "system",
"setting_id": "UgKfPuleh1xnoJLT", "setting_id": "7Q2pr70SpSjK7v7Y",
"instantiation": "true", "instantiation": "true",
"filament_max_volumetric_speed": [ "filament_max_volumetric_speed": [
"3" "3"

View File

@@ -1,8 +1,8 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic ABS @base", "name": "Generic ABS @Anker base",
"inherits": "fdm_filament_abs", "inherits": "fdm_filament_abs",
"from": "system", "from": "system",
"filament_id": "GFB99", "filament_id": "OFY9muEs",
"instantiation": "false" "instantiation": "false"
} }

View File

@@ -1,9 +1,10 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic ASA", "name": "Generic ABS @Anker",
"inherits": "Anker Generic ASA @base", "inherits": "Generic ABS @Anker base",
"renamed_from": "Anker Generic ABS",
"from": "system", "from": "system",
"setting_id": "QiFoBW5WuDUJGmFZ", "setting_id": "x3IBYtgKBx6Mszzk",
"instantiation": "true", "instantiation": "true",
"compatible_printers": [ "compatible_printers": [
"Anker M5 0.4 nozzle", "Anker M5 0.4 nozzle",

View File

@@ -1,9 +1,10 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PETG 0.2 nozzle", "name": "Generic ASA @Anker 0.2 nozzle",
"inherits": "Anker Generic PETG @base", "inherits": "Generic ASA @Anker base",
"renamed_from": "Anker Generic ASA 0.2 nozzle",
"from": "system", "from": "system",
"setting_id": "VItvDP6zmenWXwPO", "setting_id": "lTR8QLbuttyVs5UW",
"instantiation": "true", "instantiation": "true",
"filament_max_volumetric_speed": [ "filament_max_volumetric_speed": [
"2" "2"

View File

@@ -1,9 +1,10 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic ABS 0.25 nozzle", "name": "Generic ASA @Anker 0.25 nozzle",
"inherits": "Anker Generic ABS @base", "inherits": "Generic ASA @Anker base",
"renamed_from": "Anker Generic ASA 0.25 nozzle",
"from": "system", "from": "system",
"setting_id": "WS5wXckNuiQqSVwO", "setting_id": "FU4BiMydEyo7zxq5",
"instantiation": "true", "instantiation": "true",
"filament_max_volumetric_speed": [ "filament_max_volumetric_speed": [
"3" "3"

View File

@@ -1,8 +1,8 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic ASA @base", "name": "Generic ASA @Anker base",
"inherits": "fdm_filament_asa", "inherits": "fdm_filament_asa",
"from": "system", "from": "system",
"filament_id": "GFB98", "filament_id": "OFLPAxz3",
"instantiation": "false" "instantiation": "false"
} }

View File

@@ -1,9 +1,10 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PETG-CF", "name": "Generic ASA @Anker",
"inherits": "Anker Generic PETG-CF @base", "inherits": "Generic ASA @Anker base",
"renamed_from": "Anker Generic ASA",
"from": "system", "from": "system",
"setting_id": "j8PLF6AZD0R0oVs8", "setting_id": "aDADuxiEKt2dVKOJ",
"instantiation": "true", "instantiation": "true",
"compatible_printers": [ "compatible_printers": [
"Anker M5 0.4 nozzle", "Anker M5 0.4 nozzle",

View File

@@ -1,9 +1,10 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PA 0.2 nozzle", "name": "Generic PA @Anker 0.2 nozzle",
"inherits": "Anker Generic PA @base", "inherits": "Generic PA @Anker base",
"renamed_from": "Anker Generic PA 0.2 nozzle",
"from": "system", "from": "system",
"setting_id": "NZB26MSD9WbOeY2S", "setting_id": "tYAT7xnNFD6gY84A",
"instantiation": "true", "instantiation": "true",
"filament_max_volumetric_speed": [ "filament_max_volumetric_speed": [
"2" "2"

View File

@@ -1,9 +1,10 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PA 0.25 nozzle", "name": "Generic PA @Anker 0.25 nozzle",
"inherits": "Anker Generic PA @base", "inherits": "Generic PA @Anker base",
"renamed_from": "Anker Generic PA 0.25 nozzle",
"from": "system", "from": "system",
"setting_id": "Wj7oXTGUxo8lie1B", "setting_id": "Zlv65wLA94PbevRG",
"instantiation": "true", "instantiation": "true",
"filament_max_volumetric_speed": [ "filament_max_volumetric_speed": [
"3" "3"

View File

@@ -1,8 +1,8 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PA @base", "name": "Generic PA @Anker base",
"inherits": "fdm_filament_pa", "inherits": "fdm_filament_pa",
"from": "system", "from": "system",
"filament_id": "GFN99", "filament_id": "OFg8ndtj",
"instantiation": "false" "instantiation": "false"
} }

View File

@@ -1,9 +1,10 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PC", "name": "Generic PA @Anker",
"inherits": "Anker Generic PC @base", "inherits": "Generic PA @Anker base",
"renamed_from": "Anker Generic PA",
"from": "system", "from": "system",
"setting_id": "xY25QcIsR9pWai3n", "setting_id": "sLWVtBxpAC53eUwo",
"instantiation": "true", "instantiation": "true",
"compatible_printers": [ "compatible_printers": [
"Anker M5 All-Metal 0.4 nozzle", "Anker M5 All-Metal 0.4 nozzle",

View File

@@ -1,9 +1,9 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PA-CF @base", "name": "Generic PA-CF @Anker base",
"inherits": "fdm_filament_pa", "inherits": "fdm_filament_pa",
"from": "system", "from": "system",
"filament_id": "GFN98", "filament_id": "OFQLcbps",
"instantiation": "false", "instantiation": "false",
"filament_type": [ "filament_type": [
"PA-CF" "PA-CF"

View File

@@ -1,9 +1,10 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PA", "name": "Generic PA-CF @Anker",
"inherits": "Anker Generic PA @base", "inherits": "Generic PA-CF @Anker base",
"renamed_from": "Anker Generic PA-CF",
"from": "system", "from": "system",
"setting_id": "QbIiX554Yee6vb32", "setting_id": "K4LcpR0zBp5klSpb",
"instantiation": "true", "instantiation": "true",
"compatible_printers": [ "compatible_printers": [
"Anker M5 All-Metal 0.4 nozzle", "Anker M5 All-Metal 0.4 nozzle",

View File

@@ -1,9 +1,10 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PC 0.2 nozzle", "name": "Generic PC @Anker 0.2 nozzle",
"inherits": "Anker Generic PC @base", "inherits": "Generic PC @Anker base",
"renamed_from": "Anker Generic PC 0.2 nozzle",
"from": "system", "from": "system",
"setting_id": "GhIOAidtgDkzh9Aj", "setting_id": "2sSOgctcnVh9bGbQ",
"instantiation": "true", "instantiation": "true",
"filament_max_volumetric_speed": [ "filament_max_volumetric_speed": [
"2" "2"

View File

@@ -1,9 +1,10 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PC 0.25 nozzle", "name": "Generic PC @Anker 0.25 nozzle",
"inherits": "Anker Generic PC @base", "inherits": "Generic PC @Anker base",
"renamed_from": "Anker Generic PC 0.25 nozzle",
"from": "system", "from": "system",
"setting_id": "TQm9EPdenyGJMvgP", "setting_id": "h7IRuq5uekjNw4vg",
"instantiation": "true", "instantiation": "true",
"filament_max_volumetric_speed": [ "filament_max_volumetric_speed": [
"3" "3"

View File

@@ -1,8 +1,8 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PC @base", "name": "Generic PC @Anker base",
"inherits": "fdm_filament_pc", "inherits": "fdm_filament_pc",
"from": "system", "from": "system",
"filament_id": "GFC99", "filament_id": "OFLakOUI",
"instantiation": "false" "instantiation": "false"
} }

View File

@@ -1,9 +1,10 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PA-CF", "name": "Generic PC @Anker",
"inherits": "Anker Generic PA-CF @base", "inherits": "Generic PC @Anker base",
"renamed_from": "Anker Generic PC",
"from": "system", "from": "system",
"setting_id": "qdsEps11ugFHJkn7", "setting_id": "ffufXVvW95sunH1B",
"instantiation": "true", "instantiation": "true",
"compatible_printers": [ "compatible_printers": [
"Anker M5 All-Metal 0.4 nozzle", "Anker M5 All-Metal 0.4 nozzle",

View File

@@ -1,9 +1,10 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic ASA 0.2 nozzle", "name": "Generic PETG @Anker 0.2 nozzle",
"inherits": "Anker Generic ASA @base", "inherits": "Generic PETG @Anker base",
"renamed_from": "Anker Generic PETG 0.2 nozzle",
"from": "system", "from": "system",
"setting_id": "G7pzEyyhPFDnae3R", "setting_id": "67ZHuiXPyCP6Tdtr",
"instantiation": "true", "instantiation": "true",
"filament_max_volumetric_speed": [ "filament_max_volumetric_speed": [
"2" "2"

View File

@@ -1,9 +1,10 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PLA 0.25 nozzle", "name": "Generic PETG @Anker 0.25 nozzle",
"inherits": "Anker Generic PLA @base", "inherits": "Generic PETG @Anker base",
"renamed_from": "Anker Generic PETG 0.25 nozzle",
"from": "system", "from": "system",
"setting_id": "uKfcnPWdXxAGB5Ls", "setting_id": "aLuRALDt0Otbd2So",
"instantiation": "true", "instantiation": "true",
"filament_max_volumetric_speed": [ "filament_max_volumetric_speed": [
"3" "3"

View File

@@ -1,9 +1,9 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PETG @base", "name": "Generic PETG @Anker base",
"inherits": "fdm_filament_pet", "inherits": "fdm_filament_pet",
"from": "system", "from": "system",
"filament_id": "GFG99", "filament_id": "OFYPdQJh",
"instantiation": "false", "instantiation": "false",
"filament_type": [ "filament_type": [
"PETG" "PETG"

View File

@@ -0,0 +1,17 @@
{
"type": "filament",
"name": "Generic PETG @Anker",
"inherits": "Generic PETG @Anker base",
"renamed_from": "Anker Generic PETG",
"from": "system",
"setting_id": "hvV0rmnzRHJk9sMz",
"instantiation": "true",
"compatible_printers": [
"Anker M5 0.4 nozzle",
"Anker M5 0.6 nozzle",
"Anker M5 All-Metal 0.4 nozzle",
"Anker M5 All-Metal 0.6 nozzle",
"Anker M5C 0.4 nozzle",
"Anker M5C 0.6 nozzle"
]
}

View File

@@ -1,9 +1,9 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PETG-CF @base", "name": "Generic PETG-CF @Anker base",
"inherits": "fdm_filament_pet", "inherits": "fdm_filament_pet",
"from": "system", "from": "system",
"filament_id": "GFG98", "filament_id": "OFoYSJKi",
"instantiation": "false", "instantiation": "false",
"filament_type": [ "filament_type": [
"PETG-CF" "PETG-CF"

View File

@@ -0,0 +1,17 @@
{
"type": "filament",
"name": "Generic PETG-CF @Anker",
"inherits": "Generic PETG-CF @Anker base",
"renamed_from": "Anker Generic PETG-CF",
"from": "system",
"setting_id": "vCAuQeQLoXUk28ph",
"instantiation": "true",
"compatible_printers": [
"Anker M5 0.4 nozzle",
"Anker M5 0.6 nozzle",
"Anker M5 All-Metal 0.4 nozzle",
"Anker M5 All-Metal 0.6 nozzle",
"Anker M5C 0.4 nozzle",
"Anker M5C 0.6 nozzle"
]
}

View File

@@ -1,9 +1,10 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PLA 0.2 nozzle", "name": "Generic PLA @Anker 0.2 nozzle",
"inherits": "Anker Generic PLA @base", "inherits": "Generic PLA @Anker base",
"renamed_from": "Anker Generic PLA 0.2 nozzle",
"from": "system", "from": "system",
"setting_id": "j6QmCITPJoP7bWHq", "setting_id": "rCvmCzPgi4KA6nmI",
"instantiation": "true", "instantiation": "true",
"filament_max_volumetric_speed": [ "filament_max_volumetric_speed": [
"2" "2"

View File

@@ -1,9 +1,10 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic ASA 0.25 nozzle", "name": "Generic PLA @Anker 0.25 nozzle",
"inherits": "Anker Generic ASA @base", "inherits": "Generic PLA @Anker base",
"renamed_from": "Anker Generic PLA 0.25 nozzle",
"from": "system", "from": "system",
"setting_id": "ErUUDTQ7h1wNHAKT", "setting_id": "C0hNEbEueKrcYojS",
"instantiation": "true", "instantiation": "true",
"filament_max_volumetric_speed": [ "filament_max_volumetric_speed": [
"3" "3"

View File

@@ -1,8 +1,8 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PLA @base", "name": "Generic PLA @Anker base",
"inherits": "fdm_filament_pla", "inherits": "fdm_filament_pla",
"from": "system", "from": "system",
"filament_id": "GFL99", "filament_id": "OFDSrzZ8",
"instantiation": "false" "instantiation": "false"
} }

View File

@@ -1,9 +1,10 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic ABS", "name": "Generic PLA @Anker",
"inherits": "Anker Generic ABS @base", "inherits": "Generic PLA @Anker base",
"renamed_from": "Anker Generic PLA",
"from": "system", "from": "system",
"setting_id": "axEspGzFJnrnidm4", "setting_id": "GfVhcxRmt6mHSemI",
"instantiation": "true", "instantiation": "true",
"compatible_printers": [ "compatible_printers": [
"Anker M5 0.4 nozzle", "Anker M5 0.4 nozzle",

View File

@@ -0,0 +1,17 @@
{
"type": "filament",
"name": "Generic PLA Silk @Anker 0.2 nozzle",
"inherits": "Generic PLA Silk @Anker base",
"renamed_from": "Anker Generic PLA Silk 0.2 nozzle",
"from": "system",
"setting_id": "NWGiPWYmLVktDMJt",
"instantiation": "true",
"filament_max_volumetric_speed": [
"2"
],
"compatible_printers": [
"Anker M5 0.2 nozzle",
"Anker M5 All-Metal 0.2 nozzle",
"Anker M5C 0.2 nozzle"
]
}

View File

@@ -0,0 +1,17 @@
{
"type": "filament",
"name": "Generic PLA Silk @Anker 0.25 nozzle",
"inherits": "Generic PLA Silk @Anker base",
"renamed_from": "Anker Generic PLA Silk 0.25 nozzle",
"from": "system",
"setting_id": "4thKBCnYgDtnAtF5",
"instantiation": "true",
"filament_max_volumetric_speed": [
"3"
],
"compatible_printers": [
"Anker M5 0.25 nozzle",
"Anker M5 All-Metal 0.25 nozzle",
"Anker M5C 0.25 nozzle"
]
}

View File

@@ -1,9 +1,9 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PLA Silk @base", "name": "Generic PLA Silk @Anker base",
"inherits": "fdm_filament_pla", "inherits": "fdm_filament_pla",
"from": "system", "from": "system",
"filament_id": "GFL96", "filament_id": "OFesA6rF",
"instantiation": "false", "instantiation": "false",
"filament_cost": [ "filament_cost": [
"20" "20"

View File

@@ -0,0 +1,17 @@
{
"type": "filament",
"name": "Generic PLA Silk @Anker",
"inherits": "Generic PLA Silk @Anker base",
"renamed_from": "Anker Generic PLA Silk",
"from": "system",
"setting_id": "URRIeNXIiIPjxbKL",
"instantiation": "true",
"compatible_printers": [
"Anker M5 0.4 nozzle",
"Anker M5 0.6 nozzle",
"Anker M5 All-Metal 0.4 nozzle",
"Anker M5 All-Metal 0.6 nozzle",
"Anker M5C 0.4 nozzle",
"Anker M5C 0.6 nozzle"
]
}

View File

@@ -0,0 +1,17 @@
{
"type": "filament",
"name": "Generic PLA+ @Anker 0.2 nozzle",
"inherits": "Generic PLA+ @Anker base",
"renamed_from": "Anker Generic PLA+ 0.2 nozzle",
"from": "system",
"setting_id": "5m3xLxdReqLlE2Jp",
"instantiation": "true",
"filament_max_volumetric_speed": [
"2"
],
"compatible_printers": [
"Anker M5 0.2 nozzle",
"Anker M5 All-Metal 0.2 nozzle",
"Anker M5C 0.2 nozzle"
]
}

View File

@@ -0,0 +1,17 @@
{
"type": "filament",
"name": "Generic PLA+ @Anker 0.25 nozzle",
"inherits": "Generic PLA+ @Anker base",
"renamed_from": "Anker Generic PLA+ 0.25 nozzle",
"from": "system",
"setting_id": "wwkWVDsg6SoeCS0F",
"instantiation": "true",
"filament_max_volumetric_speed": [
"3"
],
"compatible_printers": [
"Anker M5 0.25 nozzle",
"Anker M5 All-Metal 0.25 nozzle",
"Anker M5C 0.25 nozzle"
]
}

View File

@@ -1,9 +1,9 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PLA+ @base", "name": "Generic PLA+ @Anker base",
"inherits": "fdm_filament_pla", "inherits": "fdm_filament_pla",
"from": "system", "from": "system",
"filament_id": "GFL95", "filament_id": "OFEWYR89",
"instantiation": "false", "instantiation": "false",
"filament_cost": [ "filament_cost": [
"25" "25"

View File

@@ -0,0 +1,17 @@
{
"type": "filament",
"name": "Generic PLA+ @Anker",
"inherits": "Generic PLA+ @Anker base",
"renamed_from": "Anker Generic PLA+",
"from": "system",
"setting_id": "MDb4CH02FxbgPNjS",
"instantiation": "true",
"compatible_printers": [
"Anker M5 0.4 nozzle",
"Anker M5 0.6 nozzle",
"Anker M5 All-Metal 0.4 nozzle",
"Anker M5 All-Metal 0.6 nozzle",
"Anker M5C 0.4 nozzle",
"Anker M5C 0.6 nozzle"
]
}

View File

@@ -1,9 +1,9 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PLA-CF @base", "name": "Generic PLA-CF @Anker base",
"inherits": "fdm_filament_pla", "inherits": "fdm_filament_pla",
"from": "system", "from": "system",
"filament_id": "GFL98", "filament_id": "OFWbdGsC",
"instantiation": "false", "instantiation": "false",
"filament_type": [ "filament_type": [
"PLA-CF" "PLA-CF"

View File

@@ -0,0 +1,17 @@
{
"type": "filament",
"name": "Generic PLA-CF @Anker",
"inherits": "Generic PLA-CF @Anker base",
"renamed_from": "Anker Generic PLA-CF",
"from": "system",
"setting_id": "5AdjHUxRi8LCU4E9",
"instantiation": "true",
"compatible_printers": [
"Anker M5 0.4 nozzle",
"Anker M5 0.6 nozzle",
"Anker M5 All-Metal 0.4 nozzle",
"Anker M5 All-Metal 0.6 nozzle",
"Anker M5C 0.4 nozzle",
"Anker M5C 0.6 nozzle"
]
}

View File

@@ -1,8 +1,8 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PVA @base", "name": "Generic PVA @Anker base",
"inherits": "fdm_filament_pva", "inherits": "fdm_filament_pva",
"from": "system", "from": "system",
"filament_id": "GFS99", "filament_id": "OFDvXujf",
"instantiation": "false" "instantiation": "false"
} }

View File

@@ -1,9 +1,10 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic PETG", "name": "Generic PVA @Anker",
"inherits": "Anker Generic PETG @base", "inherits": "Generic PVA @Anker base",
"renamed_from": "Anker Generic PVA",
"from": "system", "from": "system",
"setting_id": "FMnK9qOMiqDcGqhd", "setting_id": "HXERDaP3AgzWtmiu",
"instantiation": "true", "instantiation": "true",
"compatible_printers": [ "compatible_printers": [
"Anker M5 0.4 nozzle", "Anker M5 0.4 nozzle",

View File

@@ -1,9 +1,9 @@
{ {
"type": "filament", "type": "filament",
"name": "Anker Generic TPU @base", "name": "Generic TPU @Anker base",
"inherits": "fdm_filament_tpu", "inherits": "fdm_filament_tpu",
"from": "system", "from": "system",
"filament_id": "GFU99", "filament_id": "OFgbpcy9",
"instantiation": "false", "instantiation": "false",
"filament_retraction_speed": "90", "filament_retraction_speed": "90",
"filament_deretraction_speed": "50", "filament_deretraction_speed": "50",

View File

@@ -0,0 +1,17 @@
{
"type": "filament",
"name": "Generic TPU @Anker",
"inherits": "Generic TPU @Anker base",
"renamed_from": "Anker Generic TPU",
"from": "system",
"setting_id": "5YigkBBSP2RM1MbK",
"instantiation": "true",
"compatible_printers": [
"Anker M5 0.4 nozzle",
"Anker M5 0.6 nozzle",
"Anker M5 All-Metal 0.4 nozzle",
"Anker M5 All-Metal 0.6 nozzle",
"Anker M5C 0.4 nozzle",
"Anker M5C 0.6 nozzle"
]
}

View File

@@ -16,7 +16,7 @@
"auxiliary_fan": "0", "auxiliary_fan": "0",
"bed_exclude_area": [], "bed_exclude_area": [],
"default_filament_profile": [ "default_filament_profile": [
"Anker Generic PLA+" "Generic PLA+ @Anker"
], ],
"default_print_profile": "0.10mm Standard 0.2mm nozzle @Anker", "default_print_profile": "0.10mm Standard 0.2mm nozzle @Anker",
"extruder_clearance_height_to_lid": "250", "extruder_clearance_height_to_lid": "250",

View File

@@ -16,7 +16,7 @@
"auxiliary_fan": "0", "auxiliary_fan": "0",
"bed_exclude_area": [], "bed_exclude_area": [],
"default_filament_profile": [ "default_filament_profile": [
"Anker Generic PLA+" "Generic PLA+ @Anker"
], ],
"default_print_profile": "0.10mm Standard 0.25mm nozzle @Anker", "default_print_profile": "0.10mm Standard 0.25mm nozzle @Anker",
"extruder_clearance_height_to_lid": "250", "extruder_clearance_height_to_lid": "250",

View File

@@ -13,7 +13,7 @@
"auxiliary_fan": "0", "auxiliary_fan": "0",
"bed_exclude_area": [], "bed_exclude_area": [],
"default_filament_profile": [ "default_filament_profile": [
"Anker Generic PLA+" "Generic PLA+ @Anker"
], ],
"default_print_profile": "0.20mm Standard @Anker", "default_print_profile": "0.20mm Standard @Anker",
"extruder_clearance_height_to_lid": "250", "extruder_clearance_height_to_lid": "250",

View File

@@ -19,7 +19,7 @@
"auxiliary_fan": "0", "auxiliary_fan": "0",
"bed_exclude_area": [], "bed_exclude_area": [],
"default_filament_profile": [ "default_filament_profile": [
"Anker Generic PLA+" "Generic PLA+ @Anker"
], ],
"default_print_profile": "0.30mm Standard 0.6 nozzle @Anker", "default_print_profile": "0.30mm Standard 0.6 nozzle @Anker",
"extruder_clearance_height_to_lid": "250", "extruder_clearance_height_to_lid": "250",

View File

@@ -16,7 +16,7 @@
"auxiliary_fan": "0", "auxiliary_fan": "0",
"bed_exclude_area": [], "bed_exclude_area": [],
"default_filament_profile": [ "default_filament_profile": [
"Anker Generic PLA+" "Generic PLA+ @Anker"
], ],
"default_print_profile": "0.10mm Standard 0.2mm nozzle @Anker", "default_print_profile": "0.10mm Standard 0.2mm nozzle @Anker",
"extruder_clearance_height_to_lid": "250", "extruder_clearance_height_to_lid": "250",

View File

@@ -16,7 +16,7 @@
"auxiliary_fan": "0", "auxiliary_fan": "0",
"bed_exclude_area": [], "bed_exclude_area": [],
"default_filament_profile": [ "default_filament_profile": [
"Anker Generic PLA+" "Generic PLA+ @Anker"
], ],
"default_print_profile": "0.10mm Standard 0.25mm nozzle @Anker", "default_print_profile": "0.10mm Standard 0.25mm nozzle @Anker",
"extruder_clearance_height_to_lid": "250", "extruder_clearance_height_to_lid": "250",

View File

@@ -13,7 +13,7 @@
"auxiliary_fan": "0", "auxiliary_fan": "0",
"bed_exclude_area": [], "bed_exclude_area": [],
"default_filament_profile": [ "default_filament_profile": [
"Anker Generic PLA+" "Generic PLA+ @Anker"
], ],
"default_print_profile": "0.20mm Standard @Anker", "default_print_profile": "0.20mm Standard @Anker",
"extruder_clearance_height_to_lid": "250", "extruder_clearance_height_to_lid": "250",

View File

@@ -19,7 +19,7 @@
"auxiliary_fan": "0", "auxiliary_fan": "0",
"bed_exclude_area": [], "bed_exclude_area": [],
"default_filament_profile": [ "default_filament_profile": [
"Anker Generic PLA+" "Generic PLA+ @Anker"
], ],
"default_print_profile": "0.30mm Standard 0.6 nozzle @Anker", "default_print_profile": "0.30mm Standard 0.6 nozzle @Anker",
"extruder_clearance_height_to_lid": "250", "extruder_clearance_height_to_lid": "250",

View File

@@ -7,5 +7,5 @@
"family": "Anker", "family": "Anker",
"machine_tech": "FFF", "machine_tech": "FFF",
"model_id": "V8111v2", "model_id": "V8111v2",
"default_materials": "Anker Generic PLA;Anker Generic PLA+;Anker Generic PLA Silk;Anker Generic TPU;Anker Generic PETG" "default_materials": "Generic PLA @Anker;Generic PLA+ @Anker;Generic PLA Silk @Anker;Generic TPU @Anker;Generic PETG @Anker"
} }

View File

@@ -7,5 +7,5 @@
"family": "Anker", "family": "Anker",
"machine_tech": "FFF", "machine_tech": "FFF",
"model_id": "V8111", "model_id": "V8111",
"default_materials": "Anker Generic PLA;Anker Generic PLA+;Anker Generic PLA Silk;Anker Generic TPU;Anker Generic PETG" "default_materials": "Generic PLA @Anker;Generic PLA+ @Anker;Generic PLA Silk @Anker;Generic TPU @Anker;Generic PETG @Anker"
} }

View File

@@ -16,7 +16,7 @@
"auxiliary_fan": "0", "auxiliary_fan": "0",
"bed_exclude_area": [], "bed_exclude_area": [],
"default_filament_profile": [ "default_filament_profile": [
"Anker Generic PLA+" "Generic PLA+ @Anker"
], ],
"default_print_profile": "0.10mm Standard 0.2mm nozzle @Anker", "default_print_profile": "0.10mm Standard 0.2mm nozzle @Anker",
"extruder_clearance_height_to_lid": "250", "extruder_clearance_height_to_lid": "250",

View File

@@ -16,7 +16,7 @@
"auxiliary_fan": "0", "auxiliary_fan": "0",
"bed_exclude_area": [], "bed_exclude_area": [],
"default_filament_profile": [ "default_filament_profile": [
"Anker Generic PLA+" "Generic PLA+ @Anker"
], ],
"default_print_profile": "0.10mm Standard 0.25mm nozzle @Anker", "default_print_profile": "0.10mm Standard 0.25mm nozzle @Anker",
"extruder_clearance_height_to_lid": "250", "extruder_clearance_height_to_lid": "250",

View File

@@ -13,7 +13,7 @@
"auxiliary_fan": "0", "auxiliary_fan": "0",
"bed_exclude_area": [], "bed_exclude_area": [],
"default_filament_profile": [ "default_filament_profile": [
"Anker Generic PLA+" "Generic PLA+ @Anker"
], ],
"default_print_profile": "0.20mm Standard @Anker", "default_print_profile": "0.20mm Standard @Anker",
"extruder_clearance_height_to_lid": "250", "extruder_clearance_height_to_lid": "250",

View File

@@ -19,7 +19,7 @@
"auxiliary_fan": "0", "auxiliary_fan": "0",
"bed_exclude_area": [], "bed_exclude_area": [],
"default_filament_profile": [ "default_filament_profile": [
"Anker Generic PLA+" "Generic PLA+ @Anker"
], ],
"default_print_profile": "0.30mm Standard 0.6 nozzle @Anker", "default_print_profile": "0.30mm Standard 0.6 nozzle @Anker",
"extruder_clearance_height_to_lid": "250", "extruder_clearance_height_to_lid": "250",

View File

@@ -7,5 +7,5 @@
"family": "Anker", "family": "Anker",
"machine_tech": "FFF", "machine_tech": "FFF",
"model_id": "V81101C3", "model_id": "V81101C3",
"default_materials": "Anker Generic PLA;Anker Generic PLA+;Anker Generic PLA Silk;Anker Generic TPU;Anker Generic PETG" "default_materials": "Generic PLA @Anker;Generic PLA+ @Anker;Generic PLA Silk @Anker;Generic TPU @Anker;Generic PETG @Anker"
} }

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
"inherits": "fdm_filament_abs", "inherits": "fdm_filament_abs",
"from": "system", "from": "system",
"setting_id": "RDI26qeSRSTe0PDg", "setting_id": "RDI26qeSRSTe0PDg",
"filament_id": "GFB99", "filament_id": "OF223rZv",
"instantiation": "true", "instantiation": "true",
"filament_settings_id": [ "filament_settings_id": [
"Anycubic ABS @Anycubic Kobra 3 Max 0.4 nozzle" "Anycubic ABS @Anycubic Kobra 3 Max 0.4 nozzle"

View File

@@ -4,7 +4,7 @@
"inherits": "fdm_filament_abs", "inherits": "fdm_filament_abs",
"from": "system", "from": "system",
"setting_id": "Moc1cylP6mmSQjlb", "setting_id": "Moc1cylP6mmSQjlb",
"filament_id": "GFB99", "filament_id": "OF223rZv",
"instantiation": "true", "instantiation": "true",
"filament_settings_id": [ "filament_settings_id": [
"Anycubic ABS @Anycubic Kobra 3 Max 0.6 nozzle" "Anycubic ABS @Anycubic Kobra 3 Max 0.6 nozzle"

View File

@@ -4,7 +4,7 @@
"inherits": "fdm_filament_abs", "inherits": "fdm_filament_abs",
"from": "system", "from": "system",
"setting_id": "2xgfnUKyOUQwYWPa", "setting_id": "2xgfnUKyOUQwYWPa",
"filament_id": "GFB99", "filament_id": "OF223rZv",
"instantiation": "true", "instantiation": "true",
"filament_settings_id": [ "filament_settings_id": [
"Anycubic ABS @Anycubic Kobra 3 Max 0.8 nozzle" "Anycubic ABS @Anycubic Kobra 3 Max 0.8 nozzle"

View File

@@ -4,11 +4,14 @@
"inherits": "fdm_filament_abs", "inherits": "fdm_filament_abs",
"from": "system", "from": "system",
"setting_id": "NOiAgxA0BbvLhR1v", "setting_id": "NOiAgxA0BbvLhR1v",
"filament_id": "GFB99", "filament_id": "OF223rZv",
"instantiation": "true", "instantiation": "true",
"filament_settings_id": [ "filament_settings_id": [
"Anycubic ABS @Anycubic Kobra S1 0.4 nozzle" "Anycubic ABS @Anycubic Kobra S1 0.4 nozzle"
], ],
"filament_vendor": [
"Anycubic"
],
"filament_flow_ratio": [ "filament_flow_ratio": [
"0.95" "0.95"
], ],

View File

@@ -4,7 +4,7 @@
"inherits": "fdm_filament_abs", "inherits": "fdm_filament_abs",
"from": "system", "from": "system",
"setting_id": "MDWaiSjl89E6Edsn", "setting_id": "MDWaiSjl89E6Edsn",
"filament_id": "GFABS", "filament_id": "OF223rZv",
"instantiation": "true", "instantiation": "true",
"filament_settings_id": [ "filament_settings_id": [
"Anycubic ABS @Anycubic Kobra S1 Max 0.25 nozzle" "Anycubic ABS @Anycubic Kobra S1 Max 0.25 nozzle"

View File

@@ -4,7 +4,7 @@
"inherits": "fdm_filament_abs", "inherits": "fdm_filament_abs",
"from": "system", "from": "system",
"setting_id": "wZjVYc7dBDSKRusJ", "setting_id": "wZjVYc7dBDSKRusJ",
"filament_id": "GFABS", "filament_id": "OF223rZv",
"instantiation": "true", "instantiation": "true",
"filament_settings_id": [ "filament_settings_id": [
"Anycubic ABS @Anycubic Kobra S1 Max 0.4 nozzle" "Anycubic ABS @Anycubic Kobra S1 Max 0.4 nozzle"

View File

@@ -4,7 +4,7 @@
"inherits": "fdm_filament_abs", "inherits": "fdm_filament_abs",
"from": "system", "from": "system",
"setting_id": "AbB6JtoPRsNgmxyy", "setting_id": "AbB6JtoPRsNgmxyy",
"filament_id": "GFABS", "filament_id": "OF223rZv",
"instantiation": "true", "instantiation": "true",
"filament_settings_id": [ "filament_settings_id": [
"Anycubic ABS @Anycubic Kobra S1 Max 0.6 nozzle" "Anycubic ABS @Anycubic Kobra S1 Max 0.6 nozzle"

View File

@@ -4,7 +4,7 @@
"inherits": "fdm_filament_abs", "inherits": "fdm_filament_abs",
"from": "system", "from": "system",
"setting_id": "exX565xnrLPkYkvu", "setting_id": "exX565xnrLPkYkvu",
"filament_id": "GFABS", "filament_id": "OF223rZv",
"instantiation": "true", "instantiation": "true",
"filament_settings_id": [ "filament_settings_id": [
"Anycubic ABS @Anycubic Kobra S1 Max 0.8 nozzle" "Anycubic ABS @Anycubic Kobra S1 Max 0.8 nozzle"

Some files were not shown because too many files have changed in this diff Show More