Local Profiles¶
Local Profiles is the no-cloud path for slicer presets. Drop an OrcaSlicer or Bambu Studio export onto BamDude and the filament / process / printer presets land in the local DB — same surface area as Cloud Profiles, but without a Bambu account, without an internet round-trip on every read, and with full support for community-maintained profiles that never went through Bambu Cloud.
The two preset sources coexist. Where a name collides, Local wins — see Tier priority below.
When to use it¶
- You don't have (or don't want) a Bambu Cloud account.
- You print with community filaments that aren't in Bambu's catalog (Hatchbox, eSUN, Polymaker, FormFutura, etc.).
- You curate your own process presets for specific use-cases (production-quality vs prototype-fast) and want them version-controlled outside Bambu's servers.
- You run a non-Bambu printer through BamDude's slicer integration and need its OrcaSlicer machine config.
- You want deterministic preset behaviour — the same preset bytes, the same slice output, no surprise upstream rev.
Supported formats¶
| Extension | Contents | Detected as |
|---|---|---|
.json |
Single OrcaSlicer preset file | filament / process / printer (auto) |
.orca_filament |
OrcaSlicer single-filament bundle | filament |
.bbscfg |
OrcaSlicer / Bambu Studio config bundle (filament + process + printer) | mixed — split by directory |
.bbsflmt |
Bambu Studio filament bundle | filament |
.zip |
ZIP containing the above | mixed — auto-classified per file |
Type detection is multi-stage:
- Explicit
typefield in the JSON - ZIP directory layout (
filament/,process/,machine/) - Settings ID keys (
filament_settings_id,print_settings_id,printer_settings_id) - Content keys (
layer_height→ process;filament_type→ filament) - Name patterns (
0.20mmin the name → process)
If the heuristic gets the type wrong, run Reclassify (POST /local-presets/reclassify) to re-evaluate everything with the latest rules.
Importing¶
Settings → Local Profiles → drop file or click to pick. The import endpoint accepts either form-encoded multipart/form-data upload (UI) or programmatic POST (POST /api/v1/local-presets/import with file field).
After import you'll see one of three toast results:
| Colour | Meaning |
|---|---|
| Green | N presets imported successfully — name + count |
| Orange | M presets skipped — duplicates by name |
| Red | Errors — typically a malformed JSON inside a bundle |
Bundle imports are all-or-nothing per file: a corrupt JSON inside a ZIP doesn't abort the rest of the bundle, but the bad entry is reported separately.
Inheritance resolution¶
OrcaSlicer presets often inherit a Bambu base profile and only override a few fields ("PLA Basic at 215 °C instead of 220 °C, otherwise like the parent"). On import, BamDude:
- Detects the
inheritsfield. - Looks up the parent in the OrcaSlicer GitHub mirror (
raw.githubusercontent.com/SoftFever/OrcaSlicer/main/resources/profiles/BBL/...). - Recursively resolves the chain (max 10 levels deep — anything beyond is treated as malformed and stops there).
- Merges parent → child (child fields win on conflict).
- Stores the fully resolved preset in the local DB, plus the literal
inheritsname on the row for display. - Caches each fetched parent in
orca_base_profiles(TTL 7 days).
The cache makes repeat imports fast and keeps you out of GitHub's anonymous rate limit.
Offline imports
Presets without inherits import fully offline. Presets that need a parent need GitHub reachable on the first import — afterwards the parent is cached and the same parent serves any future preset that inherits from it. To pre-warm the cache, import a small known-parent preset over a network connection before going offline.
GitHub unreachable
If GitHub is unreachable when a preset needs its parent, the import doesn't fail — the preset is stored with only its override fields. It works, but missing-from-the-parent fields stay empty until you re-import after the cache fills.
What lives on a preset row¶
| Field | Source |
|---|---|
name |
name from the JSON |
preset_type |
filament / process / printer (auto-classified) |
source |
orcaslicer (file import) or manual (created via the UI) |
filament_type / filament_vendor |
Extracted on filament presets |
nozzle_temp_min / nozzle_temp_max |
Range from nozzle_temperature array |
pressure_advance |
K factor (string for OrcaSlicer compatibility) |
default_filament_colour |
Hex like #FF6633 |
filament_cost, filament_density |
Per-spool economics |
compatible_printers |
JSON array — drives the "for printer" filter |
setting |
The full resolved JSON blob (post-inheritance merge) |
inherits |
Literal parent name for display |
version, created_at, updated_at |
Bookkeeping |
The full resolved blob is what slicing pipelines consume. Anything you can normally read out of OrcaSlicer's preset JSON is in there.
AMS slot integration¶
Filament local presets surface in the AMS slot configuration modal exactly the same way cloud filament presets do:
- The dropdown lists local presets with a green Local badge, then cloud presets, then built-in fallbacks.
- Picking a local preset writes its
nozzle_temp_*,filament_type, anddefault_filament_colourto the slot record — same fields a cloud preset would set. - The AMS-tray tooltip and the K-profile UI both consult
_enrich_from_local_presets(incloud.py) when the cloud / built-in tables miss asetting_id— local presets are the third resolution tier.
See AMS for how slot config flows from "preset selected" to "MQTT command issued".
Tier priority¶
Three sources can answer "what's preset X?". When the slice modal asks for the merged list:
- Local (this page) — file-imported, DB-backed,
source='orcaslicer'or'manual'. Wins on name collision. - Cloud — fetched per-user from Bambu Cloud (see Cloud Profiles).
- Bundled — slicer-sidecar fallback. Bambu's stock catalog as shipped inside the OrcaSlicer image.
The unifier (/api/v1/slicer/...) deduplicates by name across tiers, keeping the highest-priority entry. So if you import Bambu PLA Basic @BBL X1C locally and have the cloud-side version too, only the local one shows — exactly the behaviour you want when a community preset diverges from upstream.
Editing a preset¶
Cards expand on click. The detail view shows every field of the resolved JSON. To edit:
| Action | Endpoint | Notes |
|---|---|---|
| Update name | PUT /api/v1/local-presets/{id} with {name} |
Cosmetic only |
| Update settings | PUT /api/v1/local-presets/{id} with {setting: {...}} |
Re-runs resolve_preset() so inheritance resolves against any new inherits value, then re-extracts core fields |
| Manual create | POST /api/v1/local-presets/ |
Bypasses the file import path — useful for on-the-fly tweaks |
There's no "save as new" affordance in the UI — that's done via duplicate-then-edit on the source file before re-importing.
Deleting¶
| Scope | Endpoint |
|---|---|
| Single | DELETE /api/v1/local-presets/{id} |
| Bulk | The list view's checkboxes + Delete-selected button (calls the single endpoint per row) |
Deletes are immediate — no trash, no undo. The on-disk file under <DATA_DIR>/local_presets/ (cache for the import) isn't trash either; it's reconstructable from the DB row, so the cache layer reaps deleted rows on the next sweep.
Base profile cache management¶
Two admin endpoints expose the parent-profile cache:
| Endpoint | What |
|---|---|
GET /api/v1/local-presets/base-cache/status |
How many parents are cached, oldest fetch timestamp, total bytes |
POST /api/v1/local-presets/base-cache/refresh |
Force-refetch every cached parent from GitHub (ignores TTL) |
Use refresh after a major OrcaSlicer release — Bambu sometimes silently fixes a base profile (bumped temp range, corrected K factor) and your cached copy lags by up to 7 days otherwise.
Permissions¶
| Permission | Grants |
|---|---|
settings:read |
List presets, inspect a preset's full JSON, read base-cache status |
settings:update |
Import, manual-create, edit, delete, reclassify, refresh base cache |
Default groups: Administrators get both, Operators get both, Viewers get only settings:read (they can browse but not import).
Why settings:*?
Local presets are configuration data — they live in the same trust tier as anything in Settings. There's no separate presets:* permission family because the permission model treats "edit a preset" and "edit smart-plug config" as the same risk class.
Where files land on disk¶
The DB stores the resolved preset JSON inline. The original uploaded file is held as a working copy under:
This isn't authoritative — the DB row is. The on-disk copy is a debugging aid (you can unzip a .bbscfg and inspect the raw OrcaSlicer source). Deleting the row deletes the directory; deleting the directory by hand triggers a re-import on the next access.
The base-profile cache lives separately in the orca_base_profiles table — DB-resident, not on disk, so it survives a <DATA_DIR> restore cleanly.
Troubleshooting¶
Import says 0 imported but the file looks valid
Probably duplicate detection — every preset in the file already exists in the DB by name. The orange skip-toast count is your signal. To re-import after editing, delete the existing row first, then re-upload.
Inheritance not resolving — preset has fewer fields than it should
GitHub was unreachable on the import. Run POST /local-presets/base-cache/refresh once the network is back, then re-upload (or PUT the preset's setting field to trigger re-resolution).
Preset classified as the wrong type
Run POST /local-presets/reclassify. If the heuristics still get it wrong, the JSON is missing both an explicit type field and the conventional content keys — add "type": "filament" (or "process" / "printer") to the source file and re-import.
AMS slot dropdown doesn't show my new local preset
The slice-modal cache has a 5-minute TTL. Close and reopen the modal, or restart the AMS slot-config dialog.
I want to share a preset bundle across installs
Export from OrcaSlicer / Bambu Studio (File → Export → Export Preset Bundle), drop the .bbscfg into the import zone on each install. The DB row format is intentionally not a stable interchange format — round-trip via the slicer's export.
Can I use both Cloud and Local at once?
Yes — they coexist. Local wins on name collision. If you want a cloud preset to override a local one, rename the local one (its DB name field) before the next slice.