← cd ../projects
screenshot — Piezario models grid
in progress desktop

Piezario

A desktop app for makers to organize a personal catalog of 3D models and work out what a print actually costs. No database, no import step — the folder on your disk is the database.

next.jselectron3d-printingtypescript

Overview

Piezario is a desktop app for keeping a personal catalog of 3D models and pricing the prints that come out of them. The name is Spanish — pieza + -ario, “a personal collection of parts”, the way a recetario is your collection of recipes.

It’s deliberately narrow. It isn’t a storefront, it isn’t a design tool, and it isn’t something you publish. It organizes the parts you already have on disk, and it tells you what each one costs you to make.

The one idea: the folder is the database

Point Piezario at a folder and it renders whatever is there. There’s no import step, no database, no admin panel, no sync. You edit a README, hit refresh, and the app has changed.

One rule drives the whole catalog:

A folder with no subfolders is a model. Its parent folders are its categories.

So models/keychains/ysisi-nametag/ is the model Ysisi nametag in the category keychains, and nesting can go as deep as you like. Everything else is derived rather than declared:

DerivedFrom
CategoryAncestor folder names
Titletitle: in frontmatter → folder name
Descriptiondescription: → the README’s first paragraph
Cover imagecover: → a *preview* / cover.* image → any image
File kindsFile extensions
Capability badgesWhich kinds of file are present

A model with no README at all still shows up — just with less on its card. That property is the whole point: the catalog can never get out of sync with the disk, because the disk is the catalog.

What’s in it

Six tabs. Three are folder-driven:

  • Models — the catalog itself, filtered and searched entirely client-side.
  • Fonts — a flat fonts/ folder rendered as a Google-Fonts-style specimen browser, for the typefaces my generator scripts draw text with.
  • Icons — nested .svg files as a resizable preview browser, with an optional Search online mode that reaches into svgapi.com’s public-domain library and saves a chosen icon straight into the folder.

Three are driven by a catalog.yaml and are editable in-app — filaments (your spools, by product and color), supplies (rings, chains, glue, priced per unit), and the global cost settings. Writes go through a single comment-preserving writer, so hand-written notes in the YAML survive being edited by the app.

Costing a print properly

This is the part I actually built it for. Piezario follows the Print Farm Academy method:

landed = raw materials + purchased materials + packaging + labor + machine
price  = landed × (1 + tax) × (1 + markup)

Two details make the numbers honest:

Raw materials carry a waste buffer. Filament weight × an efficiency factor (1.1 by default) × the per-kg rate. A slicer quotes you the cost of a print that succeeds; across a hundred parts, failures, jams and defects eat more filament than any file admits.

Machine time is a real cost. Print time × an hourly rate covering the printer wearing itself out plus the power it draws — not free just because you already own the printer.

The weights and times aren’t typed in by hand. A .3mf is a ZIP, so the app reads the sliced files in each model’s out/ folder directly. Files sitting loose in out/ are the Estimate — your reference print — while each subfolder is a real sale batch summed on its own.

The bug that justified the 3MF parser

Reading those files bought something I didn’t plan for. Bambu Studio records which extruder each part uses, so when a folder holds several variants of the same model, Piezario can compare them and check they agree about what each tool means.

If paw is tool 2 in one file and tool 3 in another, opening them together silently prints one of them in the wrong color — and you find out four hours later, holding it. Now it’s a warning on the page instead.

How it’s built

LayerTechnology
AppNext.js 16 (App Router) + React 19 + Tailwind v4 + HeroUI v3
ShellElectron 33
Thumbnailsa small numpy/matplotlib CLI that renders cover.png from an STL
Packagingelectron-builder → AppImage + Windows .exe, built in GitHub Actions

Everything runs locally; there is no backend service and nothing leaves the machine.

The interesting constraint is that Piezario can’t be a static export. It reads the tree with node:fs, opens files in your desktop’s own apps, and writes back to READMEs and catalog.yaml — so the desktop build runs the real Next server inside Electron, launched with Electron’s bundled Node via ELECTRON_RUN_AS_NODE. The window just loads http://127.0.0.1:<port>. That’s also why the packaged app needs no separate runtime installed: Electron already ships one.

Pages are force-dynamic for the same reason. The catalog changes while the server is running, so a cached render would be showing you a folder that no longer exists.

The whole thing is wired from one environment variable — CATALOG_CONFIG points at a catalog.yaml, and the app resolves models/, fonts/ and icons/ relative to it. The app has no dependency on any particular catalog, which is what lets you point it at any folder without touching code.

Status

Early but usable — it builds, packages, and I’m running it against my own catalog. Releases are cut by tagging: a GitHub Action builds the AppImage on Linux and the .exe on Windows and attaches both, so I never need a Windows machine to ship a Windows build.

Most of the work so far has been the unglamorous desktop-integration layer that decides whether an app feels native or broken: running without the Chromium sandbox so the AppImage starts on modern Linux, fixing a blank and laggy window under Wayland, matching desktop scaling so the text isn’t tiny, and setting StartupWMClass so the taskbar icon is right.

Next up is filling out the catalog side and getting more of the pricing surfaced where I actually need it — at the moment I still open a slicer more often than I’d like.