No description
  • TypeScript 53.1%
  • Python 33.5%
  • CSS 7.5%
  • Shell 3.6%
  • Nix 1.5%
  • Other 0.8%
Find a file
Julian Schubert 20d853e6bb initial commit
2026-09-27 13:32:46 +02:00
.agents/skills initial commit 2026-09-27 13:32:46 +02:00
.claude/skills/box-studio initial commit 2026-09-27 13:32:46 +02:00
data initial commit 2026-09-27 13:32:46 +02:00
docs initial commit 2026-09-27 13:32:46 +02:00
frontend/studio initial commit 2026-09-27 13:32:46 +02:00
python/fancyboxes initial commit 2026-09-27 13:32:46 +02:00
scripts initial commit 2026-09-27 13:32:46 +02:00
.envrc initial commit 2026-09-27 13:32:46 +02:00
.gitignore initial commit 2026-09-27 13:32:46 +02:00
.python-version initial commit 2026-09-27 13:32:46 +02:00
biome.json initial commit 2026-09-27 13:32:46 +02:00
flake.lock initial commit 2026-09-27 13:32:46 +02:00
flake.nix initial commit 2026-09-27 13:32:46 +02:00
justfile initial commit 2026-09-27 13:32:46 +02:00
package.json initial commit 2026-09-27 13:32:46 +02:00
pnpm-lock.yaml initial commit 2026-09-27 13:32:46 +02:00
pnpm-workspace.yaml initial commit 2026-09-27 13:32:46 +02:00
pyproject.toml initial commit 2026-09-27 13:32:46 +02:00
README.md initial commit 2026-09-27 13:32:46 +02:00
uv.lock initial commit 2026-09-27 13:32:46 +02:00

FancyBoxes

Why you might care about this repo

  • Box Studio: design round boxes with patterned walls in the browser, with a live 3D preview
  • Fluted, ribbed, faceted and wavy walls, turned as spirals, double spirals, woven lattices, zigzags, arches and more
  • Every pattern prints upright without supports, and the Studio shows how far each box leans
  • One click exports every saved box as an STL for any slicer, all on one plate

Issues this solves

  • Crossed and interleaved flutes are hard to build in CAD
    • The OCCT booleans behind build123d and CadQuery return wrong solids for them
    • Here the wall is a radius per angle and height, meshed directly, with no booleans
  • Choosing a twist that still prints
    • The twist slider is green up to the 45° limit and red beyond it
  • Printing many boxes overnight
    • Print: 2 lines makes the wall a 0.8 mm shell that follows the pattern: about 3 times faster than a solid wall, and not limited to one box like vase mode
    • Print: 1 line makes it 0.5 mm, about a third faster again

How you want to use this repo

  1. Start the Studio, and open the address it prints (http://localhost:5173):

    nix run .#studio
    
  2. Press + to start a box. Set the size and the floor height first: a side view shows how deep the inside is. A 100 mm box with its floor at 70 mm holds 30 mm, on a base the slicer fills with light infill. Then pick a shape and a twist by their pictures. Patterns has 30 ready-made ones, and Surprise me picks a random pattern that prints.

  3. The box names itself after its settings, such as "Toothpicks · spiral flutes", and the name changes with them. A name you type stays. ↺ beside it gives the box its settings' name again.

  4. Save puts the box on the shelf, data/config/boxes.json.

  5. Export to STL writes every saved box to data/stl/, one file per box, named after it. The dialog after it downloads each file, or all of them as one zip. Use this when the browser is on a different computer than the Studio.

nix run alone exports the saved boxes without the Studio, the same as the button. Both work on any machine with Nix. A git flake reads only tracked files, so git add the repo before the first run.

To use the Studio from a phone or another laptop, start it with nix run .#studio-lan. It prints the addresses to open on the other device.

Commands

just … Does
studio start Box Studio
studio-lan start Box Studio for other devices on the local network
generate export every saved box to data/stl/
check the gate before a commit: Biome, ruff, tsc, pyright, Vitest, pytest
e2e the end-to-end tests in a headless browser
slice-check slice shell walls with PrusaSlicer headless, and check they print as whole lines

Run them inside the flake: nix develop -c just check, or nix develop once. nix run and nix run .#studio need no shell.

Patterns

Shape (wallType) Cross-section
Smooth a plain circle
Flutes round grooves cut into the wall
Alternating deep and half-deep grooves in turn
Ribs round ridges on the wall
Facets a regular polygon
Waves a sine curve around the box
Twist (twistStyle) What the turn does
Spiral turns one way from floor to rim
Double spiral (knurled) cuts the pattern twisted both ways, for a diamond grid
Woven raises the pattern twisted both ways, like wickerwork
Arches (arched) crosses both ways at the floor and straightens out at the rim
Zigzag turns and turns back, bands times up the wall
Sway leans one way at the floor and the other way at the rim
Herringbone bands planks around the box that twist one way and the other in turn

Sizes that print well

  • Diameter 40–80 mm, height 20–100 mm
  • Wall: Solid (2 mm), 2 lines (0.8 mm) or 1 line (0.5 mm), for a 0.4 mm nozzle. Set NOZZLE_DIAMETER in data/config/defaults.env for another one.
  • Floor 1.5–3 mm for a deep box, 3 mm or more on tall, narrow ones so they do not tip over. A raised floor may go up to 2 mm below the rim.
  • Pattern depth 1–2 mm for flutes and ribs, 2–4 mm for waves

Print faster

PrusaSlicer's estimates for six holders on one 250 × 210 mm plate, with a generic printer profile:

0.2 mm layers 0.3 mm layers Filament
2 mm wall, round cavity 45 h 30 m 31 h 44 m 252 cm³
0.9 mm shell, two lines 12 h 25 m 10 h 02 m 103 cm³
  • Your printer's own profile is faster in absolute terms. The ratio stays about 3 to 1.
  • One Ø50 × 80 holder at 0.3 mm layers: 1 h 16 m with 2 lines, 49 m with 1 line.
  • Why 0.8 and 0.5 mm: PrusaSlicer prints them as exactly two and one lines on every wall type. A wall in between, such as the old 0.9 mm, gets short extra paths on crossing patterns. just slice-check repeats that measurement headless.
  • PrusaSlicer's spiral vase mode is faster again for one box, but it prints only one object per plate. It ignores the modeled cavity, so any STL from here works for it.

Where things are

Path Holds
python/fancyboxes/ the geometry engine and the Studio's backend (README)
frontend/studio/ the Studio's page: React, three.js (README)
data/config/boxes.json the saved boxes
data/config/defaults.env every tunable: data directory, ports, host
data/stl/ the exported STLs, gitignored
data/public/sample/ the three boxes the e2e tests start from
.claude/skills/box-studio/ how an agent runs, drives and checks the Studio
docs/decisions.md one line per decision, linked to its note