fotobuch
fotobuch turns one (or more) folder of photos into a print-ready PDF photo book, in a highly automated way.
Point it at your photos and fotobuch figures out the layout automatically:
- aspect ratios stay intact
- reading order flows naturally from top-left to bottom-right
- photos from the same event stay together on the same page
- more important photos get more space (you decide)
- optionally add titles and an appendix with metadata for each photo, automatically generated from your images’ EXIF data
Start fully automatic, then fine-tune individual pages by hand as needed.
How fotobuch works
fotobuch has a very simple data model. It stores each photo book as a pair of two files: a YAML file (.yaml) and a Typst template (.typ) tracked by Git inside a vault folder. The photo book can be read and modified through:
- the GUI — a visual, interactive interface for browsing and adjusting pages
- the CLI — scriptable commands for batch operations and automation
Both tools operate on exactly the same project data. You can mix and match: import photos with the CLI, review and tweak in the GUI, then kick off the release build from either side.
Your original photos are never modified. fotobuch only reads your source files to create cached copies at the configured DPI. Commands like
removedelete photos from the project YAML — your originals on disk are untouched.
Example project
The repository ships with a complete example in docs/examples/ — a ready-made
project with sample images and both preview and release PDFs. A good way to
explore the YAML, the Typst template, and the output without creating your own
project first.
Source code
Installation
Pre-built binaries (recommended)
Download the latest binary for your platform from the Releases page:
| Platform | File |
|---|---|
| Linux x86_64 | fotobuch-linux-x86_64.tar.gz |
| Windows x86_64 | fotobuch-windows-x86_64.zip |
| macOS arm64 (M1 and up) | fotobuch-macos-arm64.tar.gz |
Each archive contains both binaries: fotobuch (CLI) and fotobuch-gui (GUI).
Extract the archive and place them somewhere on your PATH.
Build from source
Requirements: Rust (stable).
git clone https://github.com/EddyXorb/fotobuch.git
cd fotobuch
cargo build --release --features gui
# binaries:
# cli: ./target/release/fotobuch
# gui: ./target/release/fotobuch-gui
Working with the CLI
Verify the install:
fotobuch --version
Recommended editor setup
fotobuch writes a Typst source file alongside the PDF.
For a live preview while you work, install
VS Code with the
Typst Preview
extension. Open the .typ file and the preview updates every time you run
fotobuch build.
Alternatively, just keep any PDF viewer open and reload after each build.
Shell completions
fotobuch completions --shell bash >> ~/.bash_completion
fotobuch completions --shell zsh >> ~/.zshrc
fotobuch completions --shell fish > ~/.config/fish/completions/fotobuch.fish
fotobuch completions --shell powershell >> $PROFILE
macOS: “Apple could not verify that fotobuch is free of malware”
fotobuch is not signed with an Apple Developer ID and therefore not notarized by
Apple. Anything downloaded through a browser gets the com.apple.quarantine
attribute, and Gatekeeper blocks quarantined binaries that carry no notarization
ticket — the dialog only offers Move to Trash and Done. The binary is fine;
macOS simply cannot ask Apple whether it has been checked.
Pick whichever way you prefer:
1. Install from the terminal (recommended). curl does not set the
quarantine attribute, so nothing is ever blocked:
curl -fsSL https://github.com/EddyXorb/fotobuch/releases/latest/download/fotobuch-macos-arm64.tar.gz | tar -xz
mkdir -p ~/.local/bin && mv fotobuch fotobuch-gui ~/.local/bin/
~/.local/bin/fotobuch --version
Add ~/.local/bin to your PATH if it is not there yet:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
2. Remove the quarantine flag from an existing download:
xattr -dr com.apple.quarantine ~/Downloads/fotobuch-macos-arm64
3. Without the terminal: double-click the binary, dismiss the warning, then
open System Settings → Privacy & Security, scroll to the security section
and click Open Anyway next to the message about fotobuch. Confirm once per
binary — fotobuch and fotobuch-gui are separate executables.
Apple Silicon only: the release contains an
arm64build. Intel Macs need a build from source.
Core Concepts
Projects and vaults
A fotobuch project is a pair of files tracked by Git — a YAML config, a Typst template. Multiple projects can live in the same Git repository (called a vault), each on its own branch. Switching projects is a Git checkout under the hood.
See the Glossary for precise definitions of vault, project, and template.
Photos and groups
When you import a folder, all photos in that folder become a group. Groups matter because fotobuch tries to keep photos from the same group together on the same page (or on neighbouring pages). Think of a group as “photos from one occasion”.
Each subfolder you import is a separate group. Groups are sorted chronologically — by the date in the folder name if there is one, otherwise by the oldest photo’s timestamp.
Placed vs. unplaced
A photo can be in one of two states:
| State | Meaning |
|---|---|
| unplaced | In the project, but not assigned to any page yet |
| placed | Assigned to a specific slot on a specific page |
When you build or place photos for the first time, all unplaced photos are distributed automatically across pages. After that first build, newly added photos start as unplaced and need to be placed before the next build.
Pages and slots
fotobuch arranges photos into a grid-like layout on each page. Each photo occupies a slot — a rectangular area with a specific position and size.
Both pages and slots are numbered from 0:
Page 0 Page 1 Page 2
┌──┬──┬──┐ ┌─────┬──┐ ┌──┬─────┐
│0 │1 │2 │ │ 0 │1 │ │0 │ │
├──┴──┼──┤ │ ├──┤ ├──┤ 2 │
│ 3 │4 │ ├─────┤2 │ │1 │ │
└─────┴──┘ └─────┴──┘ └──┴─────┘
Slots are ordered left-to-right, top-to-bottom (reading order).
Weights
Every photo has an area weight (default: 1.0). fotobuch uses weights to decide how much space each photo gets relative to its neighbours on the same page. But beware: the actual chosen layout can considerably deviate from the ideal weight ratios, because the solver also has to respect aspect ratios and other constraints.
- Weight 2.0 → roughly twice the area of a weight-1.0 photo
- Weight 0.5 → roughly half
Set weights at import time when you already know some photos should dominate:
fotobuch add /photos/2024-Italy --weight 2.0 # all photos in this folder get weight 2
Adjust weights per slot after placement:
fotobuch page weight 3:2 2.0 # slot 2 on page 3 gets weight 2
In the GUI: select a slot and press W, or right-click → Set weight…
Weights only affect photos on the same page. A photo with weight 3.0 gets
more space than its page-neighbours, but it has no influence on other pages.
After changing weights, run fotobuch rebuild --page N (or press R in the
GUI) to let the solver recalculate the layout for that page.
Cover
If you create a project with a cover enabled, page 0 becomes the cover. The cover spans the full width (front + spine + back) and has its own bleed and margin settings. See Cover Modes for the layout options.
The .fotobuch cache
fotobuch stores resized preview and final images in a .fotobuch/cache/ directory
inside your project folder.
This is purely a cache — delete it at any time without
losing data.
The next build regenerates whatever it needs.
Vaults and Multiple Projects
A fotobuch vault is a folder that is also a Git repository containing at least one git branch that starts with “fotobuch/”. It holds any number of fotobuch projects — each on its own branch named fotobuch/<project-name>.
When using the CLI, fotobuch looks for the vault in the current working directory only.
When using the GUI, fotobuch looks for the vault using a priority chain (see below) and opens it automatically on startup.
Branch layout
All projects share the same repository root. At any time the working tree shows the files of the currently checked-out project:
vault/
├── .git/
├── Italy-2024.yaml ← current project (checked out)
├── Italy-2024.typ
└── .fotobuch/ ← ignored by git, shared cache for all projects
└── cache/
├── Italy-2024/
└── Hiking-2025/ ← cache for project Hiking-2025, not visible in the working tree
GUI: Default vault and how fotobuch finds it
When you open fotobuch in the GUI it resolves the vault using this priority chain:
| Priority | Source | Description |
|---|---|---|
| 1 | --vault <path> CLI flag | Explicit path, overrides everything |
| 2 | FOTOBUCH_VAULT env variable | Set in shell or CI environment |
| 3 | Current working directory | Used if the directory already contains fotobuch/* branches |
| 4 | Last-used vault | Remembered from the previous session |
| 5 | Default: ~/Pictures/Fotobuch | Created automatically on first use |
The default vault path is ~/Pictures/Fotobuch (or the platform equivalent of the Pictures directory).
Configuration
Every project has a {project-name}.yaml file that controls the entire book.
You don’t need to write this file from scratch — creating a new project generates
it with sensible defaults. Edit only the parts you want to change.
For a quick overview of the most important settings to check before your first build, see Step 2 in the CLI Quickstart.
Tip: If the solver produces poor results, the most common fixes are: increase
search_timeout(more time), or disableenable_local_search. You may also want to tweak the solver weights according to your needs (e.g. increaseweight_splitif you want groups to be respected more strictly).
Full reference
The YAML has this structure:
config:
book: # page dimensions, margins, bleed, cover
cover: # cover-specific settings
book_layout_solver: # photo-to-page distribution
page_layout_solver: # single-page layout (genetic algorithm)
weights: # fitness function weights (nested)
preview: # preview rendering options
All fields below are optional unless marked otherwise. Defaults are applied automatically for any field you don’t set.
config.book — Page dimensions and layout
| Field | Default | Description |
|---|---|---|
title | "Untitled" | Book title. Used as the default spine text on the cover. |
page_width_mm | 210.0 | Page width in mm. Set at project creation with --width. The resulting PDF’s width will have exactly this width plus any bleed. If you want double-page spreads, use the combined width (e.g. 420). |
page_height_mm | 297.0 | Page height in mm. Set at project creation with --height. |
bleed_mm | 3.0 | Bleed area in mm added around each page. Only active when margin_mm is 0. Cut off by the printer. Most services require 3 mm. |
margin_mm | 0.0 | Minimum inset from the page edge. 0 = edge-to-edge (photos may bleed). > 0 = white border (bleed extension is disabled). |
gap_mm | 5.0 | Space in mm between photos on the same page. |
bleed_threshold_mm | 3.0 | Only active when margin_mm is 0. If a photo’s edge is closer to the page edge than this value, the layout is scaled so the photo extends fully into the bleed area. Prevents thin white strips at the page edge after cutting. |
dpi | 300.0 | DPI for the final release PDF. Controls the resolution of cached images used in the release build. |
config.book.cover — Cover page
All cover fields are optional. The cover is inactive by default. Enable it by
setting active: true and providing dimensions.
| Field | Default | Description |
|---|---|---|
active | false | Enable the cover. When true, the first layout entry (page 0) becomes the cover page. |
front_back_width_mm | 0.0 | Total width of front + back panel combined, without the spine. Required when active: true. |
height_mm | 0.0 | Cover height in mm. Required when active: true. |
mode | free | Cover layout mode. Controls how page 0 is solved. free = GA solver optimises freely (default). See Cover modes below. |
spine_clearance_mm | 5.0 | Gap in mm between the photo edge and the spine for front, back, and split modes. Ignored for spread modes. |
spine_text | book title | Text on the spine. Set to ~ (null) for no text. Font size is auto-calculated from the spine width (max 80% of spine width). |
spine_mode | auto | Spine width mode — see below. |
spine_mm_per_10_pages | 1.4 | Auto mode only. Spine thickness per 10 inner pages. Spine width = (inner_pages / 10) * spine_mm_per_10_pages. In auto mode the spine width affects the total cover canvas width that the solver uses. |
spine_width_mm | — | Fixed mode only. A fixed spine width in mm. In fixed mode the spine does not affect the cover canvas width in the solver — it is only used by the template for display and text sizing. |
bleed_mm | 3.0 | Same behavior as for inner pages |
margin_mm | 0.0 | Same behavior as for inner pages |
gap_mm | 5.0 | Same behavior as for inner pages |
bleed_threshold_mm | 3.0 | Same behavior as for inner pages |
Cover modes
When mode is not free, the GA solver is bypassed and slot positions are
calculated deterministically from the cover geometry. A warning is printed if
the number of photos on the cover does not match what the mode expects.
See Cover Modes — Visual Guide for visual examples of each mode.
| Mode | Photos | Behaviour |
|---|---|---|
free | any | GA solver optimises freely (default) |
front | 1 | Photo on the front panel, aspect ratio preserved and centred |
front-full | 1 | Photo fills the entire front panel (may crop) |
back | 1 | Photo on the back panel, aspect ratio preserved and centred |
back-full | 1 | Photo fills the entire back panel (may crop) |
spread | 1 | Photo spans the full spread (over spine), aspect ratio preserved and centred |
spread-full | 1 | Photo fills the full spread (may crop) |
split | 2 | Slot 0 → front, slot 1 → back, aspect ratio preserved and centred |
split-full | 2 | Slot 0 → front, slot 1 → back, each half fully filled (may crop) |
Workflow example — single photo on the front (CLI):
fotobuch place cover.jpg --into 0
# cover: { mode: front }
fotobuch rebuild --page 0
Workflow example — panorama across full spread (CLI):
fotobuch place panorama.jpg --into 0
# cover: { mode: spread-full }
fotobuch rebuild --page 0
Spine modes explained:
-
auto(default): Spine width is calculated from the number of inner pages. The formula isspine_width = (inner_pages / 10) * spine_mm_per_10_pages. The spine width is added tofront_back_width_mmto form the total cover canvas — meaning the solver accounts for the spine. -
fixed: You providespine_width_mmdirectly. The spine is not added to the canvas width — the solver usesfront_back_width_mmas-is for the cover width. The fixed spine width is only used by the template for positioning the spine text.
config.book_layout_solver — Photo-to-page distribution
The book layout solver distributes your photos across pages. It first runs an
exact dynamic program (DP) to find a globally optimal assignment, then refines
it with a local search that evaluates actual layout quality per page.
You can tweak the following parameters to control the solvers behavior in detail, but you usually only need to adjust page_target, page_max, and search_timeout.
| Field | Default | Description |
|---|---|---|
page_target | 12 | Target number of pages. The solver tries to hit this count. This is the most important solver setting. |
page_min | 1 | Hard minimum number of pages. |
page_max | 26 | Hard maximum number of pages. Setting this above page_target gives the solver room to add pages when that improves layout quality significantly. |
photos_per_page_min | 1 | Minimum number of photos on any single page. |
photos_per_page_max | 20 | Maximum number of photos on any single page. Very important: assure that your page_max multiplied by this value is greater or equal to the total number of photos. |
group_max_per_page | 5 | Maximum number of different groups that may share a single page. Lower values keep groups more separated. |
group_min_photos | 1 | When a group is split across two pages, each part must have at least this many photos. Prevents a single “orphan” photo appearing alone on the next page. |
weight_even | 1.0 | Objective weight for even photo distribution across pages. Higher = more uniform page fill. |
weight_split | 10.0 | Objective weight penalising group splits. Higher = groups are less likely to be split across pages. |
weight_pages | 5.0 | Objective weight penalising deviation from page_target. Higher = result stays closer to the target. |
search_timeout | 30s | Time budget for the local search. The DP assignment phase is exact and runs in milliseconds; this budget bounds only the refinement. YAML format: {secs: 60, nanos: 0}. |
enable_local_search | false | Whether to run the local search after the DP. The local search shifts page boundaries to improve per-page layout quality, but ignores group cohesion. Enable to trade group cohesion for tighter per-page layouts. |
max_coverage_cost | 0.95 | (Currently unused — will be removed in a future version.) Was intended as a threshold for the local search to identify “bad” pages, but is not read by the solver. |
Deprecated (optional, ignored):
mip_rel_gap,max_photos_for_splitandsplit_group_boundary_slackbelonged to the former MIP solver, which has been replaced by an exact dynamic program. They are still accepted in existing config files for backwards compatibility but have no effect, and you can safely remove them.
config.page_layout_solver — Single-page layout (genetic algorithm)
The page layout solver arranges photos within a single page using a genetic algorithm with island-model parallelism. These are advanced tuning parameters — the defaults work well for most cases.
| Field | Default | Description |
|---|---|---|
seed | 42 | Random seed for the genetic algorithm. Due to the parallelism has not a great influence on the layout as it is however not deterministic, except you are running on one core only. |
population_size | 750 | Number of individuals (candidate layouts) per island. Larger = better results but slower. |
max_generations | 100 | Maximum number of generations the algorithm runs. |
mutation_rate | 0.3 | Probability that an individual is mutated per generation. |
crossover_rate | 0.7 | Probability that two individuals are recombined per generation. |
elite_count | 20 | Number of best individuals carried over unchanged to the next generation. |
no_improvement_limit | 15 | Stop early if no improvement is found for this many generations. Set to ~ (null) to disable early stopping. |
enforce_order | true | Enforce chronological reading order (top-left to bottom-right) on each page. When true, photos are arranged so earlier photos appear before later ones in a somehow natural reading direction. Set to false if you don’t care about photo order and want the solver to optimise purely for visual quality — this often produces tighter layouts. |
islands_nr | CPU cores | Number of independent populations evolved in parallel. Defaults to the number of available CPU cores. |
islands_migration_interval | 5 | Generations between migration events (best individuals are copied between islands). |
islands_nr_migrants | 2 | Number of individuals migrated per island per migration event. |
config.page_layout_solver.weights — Fitness function
The fitness function evaluates how good a single-page layout is. It combines three cost components, each multiplied by its weight. Lower cost = better layout.
| Field | Default | Description |
|---|---|---|
w_coverage | 1.0 | Weight for canvas coverage cost. Penalises unused white space on the page. This is the dominant term. |
w_size | 0.2 | Weight for size distribution cost. Penalises photos that deviate from their target size (determined by their area_weight). |
w_barycenter | 0.0 | Weight for barycenter centering cost. Penalises layouts whose visual centre of mass is far from the page centre. Disabled by default (0.0). |
config.preview — Preview rendering
All preview overlay settings are automatically suppressed in the release build.
| Field | Default | Description |
|---|---|---|
show_filenames | false | Show the photo filename as a caption on each photo. Useful for identifying photos when adjusting the layout. |
max_preview_px | 800 | Maximum pixel size (longest edge) of cached preview images. Lower = faster builds, less disk space, blurrier preview. |
show_borders | true | Show red bleed border and blue margin border overlays on each page. |
show_slot_info | true | Show slot address and area weight on each photo (e.g. 3:2 (1.5)). |
show_preview_watermark | true | Show a watermark on the preview images. Useful to easily distinguish preview images from final output. |
write_pdf | true | Whether build/rebuild (re)write the preview PDF. Set to false to skip PDF generation (e.g. in the GUI, which renders pages directly) for faster builds. |
config.book.appendix — Photo indexu
The appendix is a compact photo index appended at the end of both the preview and release PDFs, listing every photo with its group, timestamp, and a page-position reference.
| Field | Default | Description |
|---|---|---|
active | false | Enable the photo index. |
columns | 7 | Number of columns in the listing. |
ref_mode | "positions" | Reference style: "positions" (page.slot, e.g. 2.3) or "counter" (sequential number badge on each photo). |
page_separator | false | Show a page-number header between pages in the listing. |
strip_timestamps | true | Tries to strip leading ISO timestamps from filenames in the listing. |
label_title | "Photo Index" | Localization: Title text of the appendix. |
label_page | "Page" | Localization: “Page” label used in the cross-reference legend and page separators. |
date_format | "{day}. {month} {year} {hour}:{min}" | Localization: Format string for timestamps. Placeholders: {day}, {month}, {year}, {hour}, {min}. |
date_months | ["Jan", …, "Dec"] | Localization: Month abbreviations (12 entries, January–December). |
Example: a typical YAML
config:
book:
title: "Italy 2024"
page_width_mm: 420.0 # double-page spread
page_height_mm: 297.0
bleed_mm: 3.0
margin_mm: 0.0
gap_mm: 5.0
cover:
active: true
front_back_width_mm: 594.0
height_mm: 297.0
spine_mode: auto
spine_mm_per_10_pages: 1.4
spine_text: "Italy 2024"
appendix:
active: true
label_title: "Photo Index"
label_page: "Page"
book_layout_solver:
page_target: 20
page_max: 24
photos_per_page_max: 8
search_timeout:
secs: 60
nanos: 0
preview:
show_filenames: true
show_borders: true
show_slot_info: true
max_preview_px: 800
Solver Tuning
fotobuch has two solvers: the book layout solver (exact DP + local search) distributes photos across pages; the page layout solver (genetic algorithm) arranges photos within each page. Most problems can be fixed by changing a few values in the YAML.
Curious how these solvers work under the hood? See How the Layout Engine Works.
Quick checklist
- Set
page_targetto the desired page count. - Groups splitting? → raise
weight_split. - Build too slow? → raise
search_timeout, or setenable_local_search: false.
Wrong page count
| Symptom | Fix |
|---|---|
| Too many pages | Lower book_layout_solver.page_target |
| Too few pages | Raise book_layout_solver.page_target |
| Solver ignores the target | Raise book_layout_solver.weight_pages (default 5.0) |
| Groups split across pages | Raise book_layout_solver.weight_split (default 10.0) and/or set book_layout_solver.enable_local_search: false |
Always keep page_max a few pages above page_target so the solver can use an extra page when that improves the layout significantly.
Solver too slow
The page assignment phase uses an exact dynamic program that solves even
thousand-photo books in milliseconds, so it is no longer a bottleneck. The
search_timeout (default 30 s) now bounds only the local search phase:
book_layout_solver:
search_timeout:
secs: 60
nanos: 0
enable_local_search: false # skip local search for a faster (coarser) result
Poor single-page layouts
| Symptom | Fix |
|---|---|
| Much white space | Raise page_layout_solver.weights.w_coverage (default 1.0) |
| Photo sizes don’t match weights | Raise page_layout_solver.weights.w_size (default 0.2) |
| Chronological order wrong | Set page_layout_solver.enforce_order: true (default) |
Cover Modes
Each cover mode determines how photos are positioned and sized on the cover. The examples below show the result of each mode with a sample photo.
Mode: front
A single photo on the front panel, with its aspect ratio preserved and centred.
Mode: front-full
A single photo fills the entire front panel (may crop to fit).
Mode: back
A single photo on the back panel, with its aspect ratio preserved and centred.
Mode: back-full
A single photo fills the entire back panel (may crop to fit).
Mode: spread
A single photo spans the full spread (front, spine, and back), with its aspect ratio preserved and centred.
Mode: spread-full
A single photo fills the full spread without cropping space for the spine (may crop the photo).
Mode: split
Two photos: slot 0 goes on the front panel, slot 1 on the back panel. Both have their aspect ratios preserved and are centred.
Mode: split-full
Two photos: slot 0 fills the front panel, slot 1 fills the back panel (each may crop independently).
Mode: free
The genetic algorithm solver optimises photo placement freely without constraints. Use any number of photos.
Customizing the Template
This is a quick introduction to customizing the Typst template for advanced users. You can skip this section if you are happy with the default layout.
Every project has a {name}.typ file — a Typst template
that controls how the PDF looks. fotobuch generates this file for you when you
create a new project (via the GUI New project dialog or the CLI
fotobuch project new command), but you are free to edit it. fotobuch will not
overwrite your template once created, so your changes stay safe and can be
reused across projects.
Make sure that during your edits you do not change the lines
#let is_final = false
#let project_name = "{project_name}"
#let data = yaml(project_name + ".yaml")
#set text(font: "Libertinus Serif")
otherwise it won’t compile.
Important: Always edit
{name}.typ, neverfinal.typ. The final template is auto-generated from yours during a release build (withis_final = true). Your changes infinal.typwould be overwritten.
Preview overlays
These settings only affect the preview PDF. They are automatically disabled in
the release build. Configure them in {name}.yaml:
config:
preview:
show_filenames: false # show filename caption on each photo
show_borders: true # red bleed border + blue margin border
show_slot_info: true # slot address and weight on each photo
Turn on show_filenames when you’re trying to identify which photo is where.
Turn off show_slot_info once you’re happy with the layout and just want a
clean preview.
Photo index (appendix)
The template can append a photo index at the end of the book — a compact
reference listing every photo with its group, timestamp, and a reference back to
its page position. Configure it under config.book.appendix in {name}.yaml:
config:
book:
appendix:
active: true
columns: 7
ref_mode: "positions" # or "counter"
label_title: "Photo Index"
label_page: "Page"
| Setting | Default | Effect |
|---|---|---|
active | false | Enable the appendix |
columns | 7 | Number of columns in the listing |
ref_mode | "positions" | How photos are referenced (see below) |
page_separator | false | Show a page-number header between pages |
strip_timestamps | true | Try to strip leading timestamps from filenames |
label_title | "Photo Index" | Localization: Title text |
label_page | "Page" | Localization: “Page” label |
date_format | "{day}. {month} {year} {hour}:{min}" | Timestamp format |
date_months | ["Jan", …, "Dec"] | Month abbreviations |
Reference modes
"positions" (default) — Each photo is referenced as page.slot, e.g.
2.3 means page 2, slot 3. No visual badge is added to the photos.
"counter" — Photos are numbered sequentially (1, 2, 3, …) and a small
badge with the number appears in the bottom-right corner of each photo in the
PDF.
Localization example
To produce an appendix in a different language, override the label fields and month abbreviations:
config:
book:
appendix:
active: true
columns: 6
ref_mode: "counter"
label_title: "Photo Index"
label_page: "Page"
date_format: "{day} {month} {year}"
date_months: ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
Going further
The template reads layout data from {name}.yaml via #let data = yaml(…).
A few things to keep in mind:
is_finalcontrols preview vs. release mode. Use it to conditionally show or hide elements:#if not is_final [Draft watermark].- Image paths are resolved relative to the project root via
cache_prefix. Preview images live in.fotobuch/cache/{name}/preview/, final images in.fotobuch/cache/{name}/final/.
If you want to start over with the default template, create a fresh project and
copy the generated {name}.typ back.
Printing & Export
General checklist
Before uploading your PDF, verify these things:
- Trigger a release build — only the release PDF has full 300 DPI.
Do NOT upload the preview PDF to a print service; it will look blurry.
- GUI: click Release in the toolbar (or press
Ctrl+Shift+B) - CLI:
fotobuch build release
- GUI: click Release in the toolbar (or press
- Check the output for DPI warnings (photos that are too small for their slot will be listed)
- Open the final PDF (
{name}_final.pdf) and spot-check a few pages
Saal Digital
fotobuch generates PDFs that meet Saal Digital’s technical requirements out of the box:
- Bleed: 3 mm on all sides (configurable via
config.book.bleed_mmin the YAML) - PDF boxes: MediaBox, TrimBox, and BleedBox are set correctly — matching what InDesign would produce
- Resolution: 300 DPI for the release build (configurable via
config.book.dpi)
I tested the output with Saal Digital’s online preview tool and it passed without any issues. You can upload the PDF directly to their website for printing. The only issue I had sometimes was that I did not know their spine widths exactly so I had to tweak the config.book.spine_mm setting a few times to get the preview to look right. If you know your spine width in advance, set it in the config before building and the preview should be correct on the first try.
I printed 7 photo books using fotobuch and I am quite happy with the results.
Other print services
Most print-on-demand services accept standard PDF with bleed. Adjust
config.book.bleed_mm if your provider requires a different bleed size.
The default 3 mm works for the majority of European providers.
How the Layout Engine Works (Advanced)
fotobuch lays out a book in two stages, each solved by its own algorithm:
- The book layout solver decides how many photos go on which page and which photos belong together — an exact dynamic program (DP) refined by a local search.
- The page layout solver decides how the photos on a single page are arranged — a genetic algorithm operating on slicing trees.
This page explains the ideas behind both, including a novel contribution that does not appear in the published literature. It is background reading — you never need to understand any of this to use fotobuch. For practical knobs, see Solver Tuning.
Stage 1 — Book layout solver (page assignment)
Given a chronologically ordered, grouped sequence of photos, the book layout solver partitions it into pages. A page is a contiguous slice of the sequence, so the whole problem reduces to choosing cut points in the sequence.
It runs in two phases:
- DP phase. Choosing cut points is a sequence-partitioning problem, solved
exactly by a dynamic program over states “first i photos on m pages”. The
objective balances the target page count, keeping
photo groups coherent, and respecting per-page
photo limits. Hard constraints (page count, photos per page, groups per page,
minimum group share on a split) are enforced exactly. The DP is optimal,
deterministic and runs in milliseconds even for thousand-photo books. The
derivation is documented in
docs/design/book_layout_solver_dp/dp.typ. - Local search phase. The DP optimizes a proxy objective; the local search then moves cut points based on the actual rendered layout quality, targeting pages with too much white space first (worst-first). A layout cache prevents redundant page-solver calls.
Stage 2 — Page layout solver (slicing-tree GA)
Arranging the photos within a page is the hard, visually visible part. fotobuch builds on the slicing-tree genetic algorithm described in:
O. Fan, “Photo Layout with a Fast Evaluation Method and Genetic Algorithm”, IEEE ICMEW 2012. IEEE Xplore.
A big thank-you also to @masse for collage-solver, whose work was an inspiring starting point.
Slicing trees
A page layout is encoded as a full binary tree:
- Leaves are photos.
- Internal nodes are cuts:
V(vertical cut, children side by side) orH(horizontal cut, children stacked).
For N photos the tree has N leaves and N−1 internal nodes. This structure guarantees — without any cost term — that slots align along cut lines, gaps are uniform, and nothing overlaps. The genetic algorithm only has to evolve the tree topology and the cut directions.
The genetic algorithm
- Population & islands. Several independent populations evolve in parallel on separate threads (island model), periodically migrating their best individuals. This needs no locking during evolution and converges better than a single large population.
- Mutation flips a single cut (
V ↔ H), which can change a page’s appearance dramatically. - Crossover swaps two compatible subtrees between parents, creating genuinely new topologies.
- Cost function balances coverage (minimize white space), how closely each photo’s area matches its weight, and optional centering — while aspect ratios are always kept intact.
Two contributions beyond the paper
fotobuch extends the published algorithm in two ways that materially improve both speed and result quality.
1. Exact gap computation in O(N)
The original algorithm either approximates the inter-photo gap (β) or recomputes it in O(N³) per fitness evaluation. fotobuch derives an exact closed-form solution instead.
With a gap, the relationship between a node’s width and height becomes affine:
w = α·h + γ. Each node carries a coefficient pair (α, γ) that is propagated
bottom-up through the tree:
- Leaf with aspect ratio
a:α = a,γ = 0 - V-node (children share height, widths add):
α = αₗ + αᵣ,γ = γₗ + γᵣ + β - H-node (children share width, heights add):
α = αₗ·αᵣ / (αₗ + αᵣ),γ = (γₗ/αₗ + γᵣ/αᵣ − β)·αₗ·αᵣ / (αₗ + αᵣ)
A single top-down pass then assigns exact dimensions and positions. Because
α > 0 is provably invariant for every node, the computation is always
well-defined. This reduces the per-evaluation cost from O(N³) to O(N) while
guaranteeing pixel-accurate placement with the precise gap that fills the page
with no overlap or leftover space. This formulation does not appear in the
literature.
2. Reading-order preservation via DFS indexing
A photo book tells a story, so the visual order on a page should match the
chronological order of the photos. Instead of paying a fitness penalty to nudge
the algorithm toward this, fotobuch makes it structural: photos are assigned
to leaves in depth-first pre-order. A V cut visits left before right, an H cut
visits top before bottom — so the oldest photo always lands top-left and the
sequence flows naturally to the bottom-right.
This makes correct reading order impossible to violate and removes a whole cost
term. It also enables a cheaper mutation: a cut flip changes the spatial layout
but never the depth-first leaf order, so no re-assignment is needed. You can turn
this off with enforce_order: false (see Solver Tuning).
Why it matters
Together these two ideas mean fotobuch evaluates far more candidate layouts per second and keeps your story in order by construction — which is why its many-photos-per-page results tend to look better than those of off-the-shelf tools.
Known Limitations
- photo weights are not respected cross-page-wise — will maybe be addressed in a future version
- text labels below photos/at the beginning of a new photo group are not supported — will be added in a future version
What fotobuch deliberately does not do
- No mixed page sizes within one project.
- No image editing (cropping, colour correction, rotation). Prepare your photos beforehand.
GUI Quickstart
This walkthrough takes you from zero to a print-ready PDF using the GUI.
Step 1 — Create a project
When you open fotobuch for the first time, a welcome screen appears. Click
New project, give it a name (e.g. Italy-2024), choose a folder to save
it in, and set the page dimensions in millimetres (e.g. 297 × 210 mm = A4
landscape).
fotobuch creates the project and opens it automatically.
Step 2 — Add photos
Click Add in the toolbar (or press Ctrl+O). Select a folder — all photos
in that folder are imported into the Photo Pool on the left. You can add more
folders at any time; each folder becomes a separate group.
The Photo Pool shows all your imported photos. Unplaced photos are available for placement; the count is shown at the top.
Step 3 — Fine-tune the configuration
Click Config in the toolbar to open the project configuration. Key settings:
- page_target — how many pages you want
- search_timeout — how long the solver runs (increase for large books)
- gap_mm — space between photos on a page
- book.margin_mm — inner margin around the page content (default
0.0) - book.bleed_mm — bleed zone added at the page edges, trimmed in the final PDF (default
3.0); set to0if your print service does not require bleed
Most settings preview instantly. The page and per-page targets only change how the
layout is built, so rebuild the affected pages (R) to apply them to existing pages.
Step 4 — Create pages and place photos
Click Rebuild in the toolbar (or press R) with no pages selected, then
confirm Rebuild all in the dialog. fotobuch creates all necessary pages and
distributes your photos across them automatically.
Alternatively, drag photos from the Photo Pool onto the dashed drop zones between pages in the Central Panel to create pages and place photos manually one by one.
Step 5 — Browse and adjust
Use the Nav Bar on the right to scroll through all pages and jump to any page with a click.
If a page doesn’t look right, hover over it in the Central Panel and click the ↻ button in the HUD to rebuild just that page. fotobuch re-runs the layout solver for that page and shows the updated result.
Moving and swapping photos between pages:
- Right-drag a slot in the Central Panel to start a drag.
- The toolbar mode switch (or press
M) controls the drag behaviour:- Swap — the dragged slot and the drop target exchange positions.
- Move — the dragged slot is inserted at the drop target; other slots shift.
Adjusting photo weight:
- Select a slot and press
Wto open the weight slider. - Or right-click a slot and choose Set weight…
- Higher weight = more space for that photo on the page.
Undoing changes:
- Press
Ctrl+Zto undo,Ctrl+Yto redo. - Click History in the toolbar to browse and jump to any earlier state.
Step 6 — Export for print
When you’re happy with the layout, click Release in the toolbar
(or press Ctrl+Shift+B).
fotobuch re-renders all images at full 300 DPI and writes
{project-name}_final.pdf in your project folder. The file opens automatically
when the build is done; you can also find it in the project folder as {project-name}_final.pdf.
Do not upload the regular preview PDF ({project-name}.pdf) to a print
service — it renders at screen resolution only.
See Printing & Export for print-service requirements such as bleed and colour profiles.
GUI Overview
fotobuch is a photo book layout tool. You bring in your photos, the program arranges them across pages automatically, and you export a print-ready PDF — all without any manual design work. The GUI is the main way to work with fotobuch interactively.
Window layout
The window has five areas:
| Area | Position | Purpose |
|---|---|---|
| Toolbar | Top | Quick access to all main actions |
| Photo Pool | Left | Your imported photos |
| Central Panel | Centre | The page canvas — what your book will look like |
| Nav Bar | Right | Miniature page overview for jumping around |
| Status bar | Bottom | Current state and progress messages |
How to create a photo book
See quickstart.
Multiple projects
You can keep several photo books — for example one per year or one per event. Use the project dropdown at the top-left of the toolbar to switch between projects or create new ones. All projects in the same folder are kept together, so opening that folder next time shows all of them.
CLI and GUI interoperability
The GUI and the fotobuch command-line tool operate on exactly the same project data. You can open a project in the GUI that was created and populated entirely from the CLI, or use the CLI and GUI on the same project in sequence — for example, run CLI commands for scripting or batch operations, then open the GUI for visual review and fine-tuning. The only rule is not to run both tools on the same project at the exact same time; alternating between them is completely fine.
The shared format is a YAML file and a Typst template tracked by git inside the vault, so every tool that understands git can inspect the full change history.
Central Panel
The central panel is the main editing canvas. It shows all pages in a vertical scroll column.
Canvas and zoom
- Ctrl+scroll — zoom in/out around the cursor.
- Ctrl+0 — fit page width to the available canvas.
- Zoom is stored per-session and does not affect the output.
Page image
Each page displays a preview rendered by the Typst compiler. While a re-render is pending the page shows a grey overlay with a spinner icon.
Page HUD
A small heads-up display floats below each page. It appears faintly at rest and expands on hover.
| Element | Action |
|---|---|
| Page number | Display only |
| Mode pill (✦ AUTO / ✋ MANUAL) | Click to toggle Auto ↔ Manual |
| ↻ button | Rebuild this page |
| ✕ button | Delete this page |
Drop zones
A drop zone appears between pages (and at the top/bottom of the list) when you are dragging photos from the Pool. Dropping here creates a new page and places the dragged photos onto it.
Slot overlays
When the cursor is over a page the individual photo slots are outlined. Hovering a slot highlights it; clicking selects it (add more with Ctrl+click; extend a range with Shift+click).
Selected slots can be:
- Deleted —
Deletekey unplaces photos from the selected slots. - Weight-adjusted —
Wopens the weight slider for fine-grained area control.
Manual mode
In Manual mode each slot shows a yellow ✦ handle in the SE corner. Right-mouse-drag the handle to resize, or right-mouse-drag the slot body to move. A live preview outline follows the pointer while dragging.
Photo Pool
The Photo Pool is the panel on the left side of the window. It shows all the photos you have imported into the current project. Think of it as your working collection — photos wait here until you put them on a page, and you can add more at any time.
Working with photos
| Action | Result |
|---|---|
| Click a photo | Select it (deselects others) |
Ctrl+click | Add or remove a photo from the selection |
Shift+click | Select a range of photos at once |
Ctrl+A (cursor in Pool) | Select all photos |
| Drag one or more photos | Carry them over to a page or a new-page drop area |
Delete (with photos selected) | Remove selected photos from the project |
Dragging photos onto pages
To place a photo on a specific page, click it to select it (or select several), then drag it over to that page in the Central Panel. When you release the mouse, fotobuch places the photo in the next available slot.
You can also drag photos to the dashed area between pages. Dropping there creates a brand new page and puts your photos on it.
If pages already exist, select the photos and press P — fotobuch will distribute them across the existing pages by timestamp. To create the initial layout, click Rebuild in the toolbar (with nothing selected) and confirm.
Photo states
- Unplaced — the photo has not been put on any page yet; shown normally.
- Placed — the photo is already on one or more pages; shown with a small badge.
Adding more photos
Click Add in the toolbar (or press Ctrl+O) to open a folder picker and import additional photos. Photos you have already imported are recognised automatically and skipped, even if you pick the same folder again.
Toolbar
The toolbar gives you quick access to everything you need: importing photos, laying them out, undoing mistakes, and exporting the finished book. It runs along the very top of the window and is always visible.
Buttons at a glance
| Button | Shortcut | What it does |
|---|---|---|
| Project dropdown | — | Switch between projects or create a new one → details |
| Add | Ctrl+O | Import photos from a folder → details |
| Place | P | Put selected photos onto a page → details |
| Rebuild | R | Re-calculate the layout for selected pages → details |
| Release | Ctrl+Shift+B | Build and save the final PDF → details |
| ↩ Undo / ↪ Redo | Ctrl+Z / Ctrl+Y | Step backwards or forwards through your changes → details |
| ⏱ History | — | Show a list of recent changes → details |
| ⚙ Config | Ctrl+, | Open project settings → details |
| Slot info | — | Show technical slot information on page previews |
| ⇄ Swap / → Move | M | Choose how dragging rearranges slots → details |
| ? | F1 | Open in-app help |
Project Switcher
The project dropdown at the left of the toolbar shows the name of the currently open project. Click it to open a menu.
What you can do
- Switch project — click any project name in the list to open it. Your current project is saved automatically first.
- New project — click + New project … and enter a name. fotobuch creates a fresh empty project and opens it.
- Switch folder — click ⇄ Switch vault … to pick a different folder on your computer. All projects in that folder become available in the dropdown.
Projects and folders
All your photo books live inside a single folder on your computer. You choose that folder once and fotobuch remembers it. Each project is a separate photo book — you can have as many as you like in the same folder.
Project naming rules
- Must start with a letter.
- May contain letters, digits,
.,_, and-. - No
..sequence allowed. - Maximum 50 characters.
- Must be unique within the folder.
- The exact name
fotobuchis reserved (names likefotobuch-2025are allowed).
Add Photos
The Add button (keyboard shortcut Ctrl+O) opens a folder picker so you can import photos into the current project.
How it works
- Click Add or press
Ctrl+O. - A folder picker opens. Navigate to the folder that contains your photos and confirm.
- fotobuch scans the folder and adds all supported image files to the Photo Pool.
You can import from several different folders — just click Add again. Photos you have already imported are recognised automatically and not added twice, even if you pick the same folder again.
Supported formats
JPEG, PNG, TIFF, and other common image formats are supported.
Place Photos
The Place button (keyboard shortcut P) takes the photos you have selected in the Photo Pool and puts them onto pages. The button is disabled when no photos are selected — use Ctrl+A in the Photo Pool to select all.
How it works
- With photos dragged to a page — drop photos from the Photo Pool directly onto a page in the canvas to place them there.
- Without a specific target — press
Pand fotobuch distributes the selected photos across existing pages, choosing the best fit based on photo timestamps.
Tip
For the fastest workflow: import your photos, press R (Rebuild) to let fotobuch create all pages and fill them automatically. Then use Place or drag-and-drop to adjust specific pages.
Rebuild Layout
The Rebuild button tells fotobuch to recalculate the layout for the selected pages. Each page in the Central Panel also has a small ↻ button in its HUD — clicking it rebuilds that single page directly without selecting it first.
Targeted rebuild — pages selected
Select one or more pages in the Nav Bar or Central Panel, then press R (or click Rebuild in the toolbar). fotobuch recalculates the arrangement of photos already on those pages. Photo assignments between pages are not changed.
The button label shows how many pages will be rebuilt.
Full rebuild — nothing selected
Click the Rebuild button in the toolbar with no pages selected and confirm when prompted. fotobuch redistributes all photos across pages from scratch, then recalculates the arrangement for every page. Use this to create the initial layout after adding photos, or to start fresh.
Note: The
Rkeyboard shortcut only triggers a rebuild when at least one page is selected. With no selection, use the toolbar button to open the confirmation dialog.
Note on results
Rebuild may produce the same layout as before if the current arrangement is already a good fit for the given photos and settings.
Release (Export PDF)
The Release button (keyboard shortcut Ctrl+Shift+B) builds the final, high-resolution PDF of your photo book and saves it to your project folder.
What “release” means
While you are working, fotobuch shows quick preview renders at screen resolution. The Release export renders all pages at full print quality — the file you would send to a print shop.
Where the PDF is saved
The PDF is saved inside your project folder as {project-name}_final.pdf. After the export finishes, the file opens automatically with your system’s default PDF viewer.
Undo, Redo and History
fotobuch keeps a full history of every change you make, so you can always go back.
Undo and Redo
| Button | Shortcut | Action |
|---|---|---|
| ↩ | Ctrl+Z | Undo the last change |
| ↪ | Ctrl+Y or Ctrl+Shift+Z | Redo (bring back an undone change) |
You can undo and redo as many steps as you like.
History panel
Click ⏱ History in the toolbar to open the history panel on the right side. It lists every saved change in order, newest first, so you can see exactly what was done and when.
The history is stored as a series of snapshots. Each change you make — placing photos, rebuilding a page, changing settings — is a separate entry in the list.
Technical: git as the underlying mechanism
fotobuch stores each project as a git repository. Every command that modifies the project creates a git commit. This means:
- The CLI and the GUI share the same history. A change made from the command line appears in the GUI history panel, and vice versa.
- Undo uses
git reset --hardto move HEAD back. Undone commits are no longer visible ingit logbut are saved in.fotobuch/redo-stacksoredocan restore them. Making a new change after an undo clears the redo stack permanently. - The full history up to the current HEAD is visible in any git client via
git log.
Configuration Panel
The ⚙ Config button (keyboard shortcut Ctrl+,) opens the project configuration panel on the right side of the window.
What you can configure
The configuration panel lets you adjust the settings for the current project:
- Paper size — the physical dimensions of your book pages (e.g. A4, square).
- Margins and bleed — how much white space to leave around photos and how much extra to add for the print edge.
- Photos per page — the target number of photos on each page when the layout is calculated automatically.
- Preview options — whether to show slot information on the page previews.
Applying changes
Changes you make in the configuration panel are applied right away — the page previews update on their own, with no separate save or apply step.
The one exception is the photos per page target: it only influences how the automatic layout distributes photos across pages, so existing pages keep their current arrangement until you rebuild them (press R or click Rebuild).
For a full list of all available configuration keys and their accepted values, see the Configuration reference.
Drag Mode (Swap and Move)
The ⇄ Swap and → Move buttons control what happens when you drag an image with the right mouse button in the Central Panel. Toggle between them with the M key.
Swap mode (⇄)
Dragging an image and dropping it on another exchanges the two photos.
When both images have the same aspect ratio, the exchange is immediate and both positions stay the same.
When the images have different aspect ratios:
- Same page — the swap is blocked. Auto mode re-sorts photos by aspect ratio when the page is recalculated, so the exchange would be undone immediately. Use Move mode to relocate photos between slots on the same page.
- Different pages — the swap goes through, but both affected pages may be recalculated to fit the new photo proportions, which can change the visual layout of those pages.
Move mode (→)
Dragging an image and dropping it elsewhere relocates it there. Only the photo itself and its aspect ratio travel with it — on an automatic page the exact size and position are recalculated to fit the destination, so the result won’t necessarily match the spot where you dropped it.
- Drop on a slot on a different page to move the photo there.
- Drop on the Nav Bar to move the photo to that page.
- Moving within the same page is only possible in Manual mode. In Auto mode, use Swap instead (if ratios match), or switch to Manual mode first.
Which mode to use
- Swap for quick reordering of same-ratio images — page layout stays intact.
- Move to shift a photo to a completely different page or to reposition in Manual mode.
Nav Bar
The Nav Bar (right side) shows thumbnail previews of all pages. It is useful for an overview when zoomed in on the canvas.
Interaction
| Action | Result |
|---|---|
| Click a thumbnail | Select that page for navigation |
| Ctrl+click | Toggle page in the multi-selection |
| Shift+click | Extend page selection |
| Drag selected thumbnails | Reorder pages (drop between other thumbnails) |
| Delete (with pages selected) | Delete selected pages (cover page is protected) |
Scroll sync
Clicking a thumbnail scrolls the central canvas to that page. The canvas scroll position does not feed back into the Nav Bar (the bar is always fully visible).
Keyboard Shortcuts
Navigation
| Key | Action |
|---|---|
Home | Scroll to first page |
End | Scroll to last page |
Ctrl+G | Open Go-to-page dialog |
Ctrl+0 | Fit page width to canvas |
Ctrl+scroll | Zoom in/out |
Editing
| Key | Action |
|---|---|
P | Place selected pool photos (auto-distribute if no page hovered) |
R | Rebuild selected pages (requires at least one page selected; use toolbar button for full rebuild) |
A | Toggle Auto/Manual mode for hovered or selected page |
Delete | Unplace selected slots / remove selected pool photos / delete selected pages |
W | Open weight slider for selected slots |
M | Toggle drag mode (Swap ↔ Move) |
History
| Key | Action |
|---|---|
Ctrl+Z | Undo |
Ctrl+Y | Redo |
Ctrl+Shift+Z | Redo (alternative) |
Selection
| Key | Action |
|---|---|
Ctrl+A | Select all (pool photos or page slots, depending on focus) |
Shift+click | Extend selection |
Ctrl+click | Toggle item in selection |
Escape | Clear all selections and cancel active drag |
Application
| Key | Action |
|---|---|
Ctrl+O | Add photos (folder picker) |
Ctrl+, | Toggle configuration panel |
Ctrl+Shift+B | Build release PDF |
F1 | Open in-app help |
F2 | Toggle frame-timing panel (debug) |
CLI Quickstart
This walkthrough takes you from zero to a print-ready PDF using the command line.
Prerequisites: fotobuch installed, a folder of photos on your machine.
Prefer learning by example? Check out the complete project in
docs/examples/— it has sample images, YAML config, template, and generated PDFs.
Step 1 — Create a project
fotobuch project new "Italy-2024" --width 297 --height 210
This creates a directory Italy-2024/ with a Git repo, a YAML config, and a
Typst template. The --width and --height values are in millimetres
(297 × 210 mm = A4 landscape).
Switch into the project folder:
cd "Italy-2024"
Project names must start with a letter and can only contain letters, digits, or dashes.
Step 2 — Review the configuration
Before adding photos, open Italy-2024.yaml in a text editor and check the
most important settings. The file already has sensible defaults, but you should
set the page count to match the size of book you want:
config:
book:
page_width_mm: 297.0
page_height_mm: 210.0
bleed_mm: 3.0 # required by most print services
margin_mm: 0.0 # 0 = edge-to-edge; set to e.g. 10 for a white border
gap_mm: 5.0 # the gap between the photos in your layout
book_layout_solver:
page_target: 20 # how many pages you want
page_max: 24 # upper limit — give the solver some room above the target
Setting page_max a few pages above page_target gives the solver freedom to
use an extra page when that produces a significantly better layout.
If you plan to use a cover:
cover:
active: true
front_back_width_mm: 594.0 # total width of front + back panel
height_mm: 297.0
spine_text: "Italy 2024"
spine_width_mm: 15.0 # spine width (does not add to front_back_width_mm when spine_mode = fixed)
spine_mode: fixed
See Configuration for a full reference of all settings.
Step 3 — Add photos
Point fotobuch at one or more folders. Each folder becomes a group — photos from the same group are kept together on pages.
fotobuch add /photos/2024-07-Italy
fotobuch add /photos/2024-08-Hiking
Folders with a date in the name are sorted chronologically. You can also add single files, add recursively, or filter by filename or XMP metadata:
# recursive — each subfolder becomes a group
fotobuch add --recursive /photos/2024-summer
# only 3-to-5-star photos, giving them more space
fotobuch add /photos/2024-07-Italy --filter-xmp "Rating.*[3-5]" --weight 5
Check what was imported:
fotobuch status
Step 4 — Build a preview
fotobuch build
On the first run, fotobuch distributes all photos across pages automatically and
renders a preview PDF at lower DPI (fast). Open Italy-2024.pdf to review the
result.
Step 5 — Adjust the layout
Move a photo to another page:
fotobuch page move 3:2 to 5
Swap two photos:
fotobuch page swap 2:3 2:7
Swap two pages:
fotobuch page swap 3 7
Split a page:
fotobuch page split 3:2
Combine pages:
fotobuch page combine 3..7
Give a photo more space (weight > 1 = relatively larger):
fotobuch page weight 3:2 2.0
Re-solve a single page:
fotobuch rebuild --page 6
Undo any change:
fotobuch undo
See CLI Concepts for slot address syntax.
Rebuild the preview after changes: fotobuch build.
Step 6 — Adding more photos later
After the first build, newly added photos start as unplaced. Place them before building:
fotobuch add /photos/bonus-shots
fotobuch place
fotobuch build
You can also place onto a specific page:
fotobuch place --into 4
fotobuch place --filter "DSC_00.*\.jpg" --into 6
Step 7 — Export for print
When you’re happy with the layout:
fotobuch build release
This re-renders all images at 300 DPI and writes Italy-2024_final.pdf.
The file is ready to upload to your print service.
See Printing for Saal Digital-specific details.
Command Overview
All commands follow the pattern fotobuch <command> [options].
Run fotobuch --help or fotobuch <command> --help for details,
or see the Full Flag Reference.
Commands at a glance
| Command | What it does |
|---|---|
project new | Create a new photobook project |
project list | List all projects in the current repo |
project switch | Switch to another project (checks out its Git branch) |
init | Alias for project new (shorthand for first-time setup) |
add | Import photos or folders into the project |
remove | Delete photos from the project entirely |
place | Assign unplaced photos to pages |
unplace | Remove photos from their page slots (they stay in the project) |
build | Solve layout and render preview PDF |
build release | Render final PDF at full resolution (300 DPI) |
rebuild | Re-run the solver on specific pages |
page move | Move photos between pages |
page swap | Swap pages or slots |
page split | Split a page at a slot |
page combine | Merge pages together |
page info | Show photo metadata for slots on a page |
page weight | Set the area weight for one or more slots |
page mode | Toggle a page between auto (solver) and manual placement |
page pos | Move or scale slots on a manual-mode page |
status | Show project overview (or single-page detail) |
config show | Print the resolved configuration with all defaults |
config set | Set a config value using dot-notation (e.g. book.dpi 150) |
history | Show the project change log |
undo | Undo the last N changes |
redo | Redo N undone changes |
For all flags and exact syntax see the Full Flag Reference. For available config keys see Configuration.
remove vs. unplace
removedeletes photos from the project. They are gone (unless youundo).unplacetakes photos off their page but keeps them in the project. They become unplaced and can be re-placed withfotobuch place.
Use remove --keep-files if you want remove-like pattern matching but
unplace-like behaviour (photos stay, just lose their page assignment).
Use remove --unplaced to delete all photos that are not yet assigned to
any page in one step (no pattern argument needed):
fotobuch remove --unplaced
build vs. rebuild
-
buildrenders the PDF and only re-solves pages that changed since the last build. On the first run it solves everything. -
rebuild --page Nforces the solver to re-optimize page N from scratch, even if nothing changed. Useful when you’re not happy with a layout. -
rebuild --allre-solves every page. -
rebuild --range-start A --range-end Bre-solves pages A through B (0-based, inclusive). Add--flex Nto let the solver vary the page count in that range by ±N:fotobuch rebuild --range-start 3 --range-end 7 --flex 2
place --into-new-page-at
place --into places photos onto an existing page. --into-new-page-at <POS>
creates a new page at position POS and places the selected photos there:
fotobuch place --filter "panorama.*" --into-new-page-at 4
CLI Concepts
Slot addresses
A slot address identifies one or more placed photos on a specific page:
| Address | Meaning |
|---|---|
3 | All slots on page 3 |
3:2 | Slot 2 on page 3 |
3:2..5 | Slots 2 through 5 on page 3 |
3:2..5,7 | Slots 2–5 and slot 7 on page 3 |
4+ | New page inserted after page 4 (move destination only) |
Use fotobuch status <page> to see which slot numbers are on a given page.
Two ways to address photos
| Method | Use case | Examples |
|---|---|---|
| Filename / pattern | Photos not yet placed, or matching by source path | add, remove, place --filter |
| Slot address | Photos already placed on a page | page move, page swap, page weight |
Rule of thumb: use filename patterns for unplaced photos (add, place,
remove); use slot addresses for placed photos (page move, page swap,
page weight, unplace).
Build pipeline
fotobuch add → photos enter the project (unplaced)
fotobuch place → unplaced photos get assigned to pages
fotobuch build → solver optimises layout, renders preview PDF
fotobuch build release → renders final PDF at print resolution
The first build implicitly places all photos, so you can skip place on a
fresh project.
Every command that changes the layout creates a Git commit automatically.
Use fotobuch undo / fotobuch redo to navigate history, and
fotobuch history to see the log.
XMP metadata filtering
fotobuch add supports --filter-xmp <REGEX> to import only photos whose XMP
metadata matches a pattern. The regex is applied to the raw XMP XML string
embedded in the image file — not to parsed fields.
Because XMP is XML, a tag like xmp:Rating appears in the raw text as e.g.
<xmp:Rating>4</xmp:Rating>. A regex therefore needs to match against that
XML text. Use exiftool -xmp -b <file.jpg> to inspect the exact XMP of a
specific photo and build your pattern from it.
Common use cases:
# Only photos with a star rating element present (any value)
fotobuch add /photos --filter-xmp "xmp:Rating"
# Only photos rated 3, 4, or 5 stars
fotobuch add /photos --filter-xmp "xmp:Rating>[3-5]<"
# Multiple filters (all must match — AND logic)
fotobuch add /photos --filter-xmp "xmp:Rating>[4-5]" --filter-xmp "dc:subject"
Photos without any XMP data are excluded when --filter-xmp is used.
Use --filter instead if you want to match by filename or source path.
Use --dry (or -d) to preview which photos would be imported without making
any changes — essential for iterating on XMP regexes before committing:
fotobuch add /photos --filter-xmp "xmp:Rating>[4-5]" --dry
Manual Mode
In Auto mode (default) the solver controls every slot on a page. Manual mode freezes the slot layout so the solver never touches it — useful for a specific page that needs a custom arrangement.
Switching a page to manual mode
fotobuch page mode 3 manual # page 3 → Manual
fotobuch page mode 3 auto # page 3 → Auto (solver takes over again)
fotobuch page mode 3,5,7 manual # several pages at once
fotobuch page mode 2..6 manual # page range
Shorthand: m = manual, a = auto.
Repositioning slots (page pos)
The page must already be in Manual mode. All values are in millimetres relative to the page content area (excluding bleed):
# Relative move: right +20 mm, down +10 mm
fotobuch page pos 3:2 --by 20,10
# Absolute position: top-left corner at (50, 30) mm
fotobuch page pos 3:1 --at 50,30
# Scale to 1.5× (grows right and downward from current position)
fotobuch page pos 3:0 --scale 1.5
# Combine absolute position and scale
fotobuch page pos 3:0 --at 10,10 --scale 2.0
--by and --at are mutually exclusive. --scale can be combined with either.
Notes
rebuild --page Non a Manual page is a no-op — the solver is bypassed. Switch to Auto first if you want a fresh solver run.- The page mode is stored in the YAML. Auto is the implicit default (the field is omitted for Auto pages).
Headless / CI Usage
The fotobuch binary has no GUI dependencies and runs in any headless environment — CI servers, Docker containers, SSH sessions.
Minimal build script
#!/bin/bash
set -e
fotobuch project new MyBook --width 297 --height 210 --quiet
cd MyBook
fotobuch add /mnt/photos/2024-Summer
fotobuch build
fotobuch build release
# MyBook_final.pdf is ready
Docker example
FROM debian:bookworm-slim
COPY fotobuch /usr/local/bin/fotobuch
WORKDIR /vault
ENTRYPOINT ["fotobuch"]
Mount the vault as a volume:
docker run --rm -v /data/vault:/vault fotobuch build release
Full Flag Reference
This page is auto-generated from the CLI source. Run
cargo run --bin generate-cli-docs --features cli-docsto regenerate.
Command-Line Help for fotobuch
This document contains the help content for the fotobuch command-line program.
Command Overview:
fotobuch↴fotobuch add↴fotobuch build↴fotobuch build release↴fotobuch rebuild↴fotobuch place↴fotobuch unplace↴fotobuch page↴fotobuch page move↴fotobuch page split↴fotobuch page combine↴fotobuch page swap↴fotobuch page info↴fotobuch page weight↴fotobuch page mode↴fotobuch page pos↴fotobuch remove↴fotobuch status↴fotobuch config↴fotobuch config show↴fotobuch config set↴fotobuch history↴fotobuch undo↴fotobuch redo↴fotobuch project↴fotobuch project new↴fotobuch project list↴fotobuch project switch↴fotobuch init↴fotobuch completions↴
fotobuch
Photobook layout solver and project manager
Usage: fotobuch <COMMAND>
Subcommands:
add— Add photos to the projectbuild— Calculate layout and generate preview or final PDFrebuild— Force re-optimization of pages or page rangesplace— Place unplaced photos into the bookunplace— Remove photos from the layout at a page:slot address (they stay in the project)page— Page manipulation commands (move, split, combine, swap)remove— Remove photos or groups from the bookstatus— Show project statusconfig— Configuration commands (show or mutate)history— Show project change historyundo— Undo the last N commits (default: 1)redo— Redo N previously undone commits (default: 1)project— Project management commandsinit— Create a new photobook project (alias forproject new)completions— Print shell completion script to stdout
fotobuch add
Add photos to the project
Usage: fotobuch add [OPTIONS] [PATHS]...
Arguments:
<PATHS>— Directories or files containing photos to add
Options:
-
--allow-duplicates— Allow adding duplicate photos (by hash) -
--filter-xmp <REGEX>— Only include photos whose XMP metadata matches this regex (can be repeated, all must match) -
--filter <REGEX>— Only include photos whose source path matches this regex pattern (can be repeated, all must match) -
-d,--dry— Preview what would be added without writing anything -
--update— Re-add photos whose path already exists but whose content has changed -
-r,--recursive— Scan directories recursively (each subdir becomes its own group) -
--weight <WEIGHT>— Area weight for all imported photos (default: 1.0)Default value:
1
fotobuch build
Calculate layout and generate preview or final PDF
Usage: fotobuch build [OPTIONS] [COMMAND]
Subcommands:
release— Generate final high-quality PDF at 300 DPI
Options:
--pages <PAGES>— Only rebuild specific pages (0-based, comma-separated or repeated flag)
fotobuch build release
Generate final high-quality PDF at 300 DPI
Usage: fotobuch build release [OPTIONS]
Options:
--force— Force release even if layout has uncommitted changes
fotobuch rebuild
Force re-optimization of pages or page ranges
Usage: fotobuch rebuild [OPTIONS]
Options:
-
--page <PAGE>— Single page to rebuild (0-based index) -
--range-start <RANGE_START>— Start of page range (0-based index, requires –range-end) -
--range-end <RANGE_END>— End of page range (0-based index, inclusive, requires –range-start) -
--flex <FLEX>— Allow page count to vary by +/- N (only with range)Default value:
0 -
--all— Rebuild all pages from scratch
fotobuch place
Place unplaced photos into the book
Usage: fotobuch place [OPTIONS]
Options:
--filter <REGEX>— Only place photos matching this regex pattern (can be repeated, all must match)--into <INTO>— Place all matching photos onto this specific page (0-based index)--into-new-page-at <POS>— Create a new page at this position and place photos there (0-based index)
fotobuch unplace
Remove photos from the layout at a page:slot address (they stay in the project)
The page is deleted automatically if it becomes empty.
Usage: fotobuch unplace <ADDRESS>
Arguments:
<ADDRESS>— Slot address: “3:2” (slot 2 on page 3), “3:2,7”, “3:2..5”, “3:2..5,7”
fotobuch page
Page manipulation commands (move, split, combine, swap)
Usage: fotobuch page <COMMAND>
Subcommands:
move— Move or unplace photos between pagessplit— Split a page at a slot: photos from that slot onwards move to a new page inserted aftercombine— Merge pages onto the first one, then delete the now-empty source pagesswap— Swap photos between two addresses (only single numbers or ranges, no comma lists)info— Show photo metadata for slots on a pageweight— Set area_weight for one or more slotsmode— Toggle page mode between auto (solver) and manual (user-placed)pos— Reposition or rescale slots on a Manual-mode page
fotobuch page move
Move or unplace photos between pages
Two forms: “SRC to DST” (move) and “SRC out” (unplace).
Addressing: 3 = whole page, 3:2 = slot 2 on page 3, 3:1..3,7 = slots 1-3 and 7, 4+ = new page after 4.
Move examples: “3:2 to 5”, “3,4 to 5”, “3:2 to 4+”. Unplace examples: “3 out”, “3:2 out”.
See the documentation for the full addressing syntax.
Usage: fotobuch page move [ARGS]...
Arguments:
<ARGS>— Expression passed as space-separated tokens, e.g.: 3:2 to 5
fotobuch page split
Split a page at a slot: photos from that slot onwards move to a new page inserted after
Shortcut for page move PAGE:SLOT.. to PAGE+. Error if SLOT is the first slot (would leave the original page empty).
Usage: fotobuch page split <ADDRESS>
Arguments:
<ADDRESS>— Address “PAGE:SLOT”, e.g. “3:4” splits page 3 at slot 4
fotobuch page combine
Merge pages onto the first one, then delete the now-empty source pages
All following page numbers shift down accordingly.
Usage: fotobuch page combine <PAGES>
Arguments:
<PAGES>— Pages expression: “3,5” (page 5 onto 3) or “3..5” (pages 4-5 onto 3)
fotobuch page swap
Swap photos between two addresses (only single numbers or ranges, no comma lists)
Page swap: “3 5” swaps pages, “1..2 5..9” swaps blocks. Slot swap: “3:2 5:6” swaps individual slots, “3:2..4 5:6..9” swaps slot ranges (different sizes ok).
Errors on overlapping ranges or comma-separated lists as operands.
Usage: fotobuch page swap <LEFT> <RIGHT>
Arguments:
<LEFT>— Left address: “3:2”, “3:1..3”, “3”, “3..6”<RIGHT>— Right address: “5:6”, “5:2..4”, “5”, “8..11”
fotobuch page info
Show photo metadata for slots on a page
Address forms: 3 (all slots), 3:2 (single slot), 3:1..3,7 (slots 1–3 and 7).
Without flags: full table (or vertical view for a single slot). With a flag: machine-readable single-field output.
Usage: fotobuch page info [OPTIONS] <ADDRESS>
Arguments:
<ADDRESS>— Address: “3”, “3:2”, “3:1..3,7”
Options:
--weights— Output only area weights (format: page:slot=weight)--ids— Output only photo IDs--pixels— Output only pixel dimensions
fotobuch page weight
Set area_weight for one or more slots
Examples: 3:2 2.0 (single slot), 3:1..3,7 2.0 (multiple slots), 3 2.0 (whole page).
Usage: fotobuch page weight <ADDRESS> <WEIGHT>
Arguments:
<ADDRESS>— Address: “3”, “3:2”, “3:1..3,7”<WEIGHT>— Weight value (must be > 0)
fotobuch page mode
Toggle page mode between auto (solver) and manual (user-placed)
Syntax: fotobuch page mode <pages> <a|m|auto|manual>
Examples: 3 m (page 3 to manual), 3..5 a (pages 3-5 to auto).
Usage: fotobuch page mode <PAGES> <MODE>
Arguments:
<PAGES>— Pages to change: “3”, “3..5”, “3,5”<MODE>— Mode: ‘a’ or ‘auto’ for auto-solver, ‘m’ or ‘manual’ for manual placement
fotobuch page pos
Reposition or rescale slots on a Manual-mode page.
Syntax: fotobuch page pos <address> [--by dx,dy] [--at x,y] [--scale s]
Examples: 4:2 --by -20,30 — move slot 2 on page 4 relatively 4:2 --at 100,50 — set slot 2 origin to (100mm, 50mm) 4:2 --scale 1.5 — scale slot 2 by 1.5× 4:2..5 --by -20,30 — move slots 2–5 together 4:2 --at 100,50 --scale 2 — absolute position + scale
At least one of –by, –at, –scale is required. –by and –at are mutually exclusive. The page must be in manual mode.
Usage: fotobuch page pos <--by <BY>|--at <AT>|--scale <SCALE>> <ADDRESS>
Arguments:
<ADDRESS>— Address: “4:2”, “4:2..5”, “4:1,3”
Options:
--by <BY>— Relative move in mm: “dx,dy” (e.g. “-20,30”)--at <AT>— Absolute position in mm: “x,y” (e.g. “100,50”)--scale <SCALE>— Scale factor applied to width and height (origin stays fixed)
fotobuch remove
Remove photos or groups from the book
Usage: fotobuch remove [OPTIONS] [PATTERNS]...
Arguments:
<PATTERNS>— Photos, group names, or regex patterns to remove (can be repeated)
Options:
--keep-files— Only remove from layout, keep photos in the project (makes them unplaced)--unplaced— Remove all photos that are not placed in any layout page
fotobuch status
Show project status
Usage: fotobuch status [PAGE]
Arguments:
<PAGE>— Show detailed information for a specific page (0-based index)
fotobuch config
Configuration commands (show or mutate)
Usage: fotobuch config <COMMAND>
Subcommands:
show— Show resolved configuration with defaultsset— Set a config value using dot-notation (e.g.book.dpi 300)
fotobuch config show
Show resolved configuration with defaults
Usage: fotobuch config show
fotobuch config set
Set a config value using dot-notation (e.g. book.dpi 300)
Supported keys mirror the YAML config hierarchy. Types are auto-detected: true/false → bool, integers → int, decimals → float, else string.
Usage: fotobuch config set <KEY> <VALUE>
Arguments:
<KEY>— Dot-notation key, e.g. “book.dpi” or “book.cover.active”<VALUE>— New value, e.g. “300”, “true”, “3.5”, “spread”
fotobuch history
Show project change history
Usage: fotobuch history [OPTIONS]
Options:
-
-n <COUNT>— Number of entries to show (0 = all)Default value:
5
fotobuch undo
Undo the last N commits (default: 1)
Usage: fotobuch undo [STEPS]
Arguments:
-
<STEPS>— Number of steps to undoDefault value:
1
fotobuch redo
Redo N previously undone commits (default: 1)
Usage: fotobuch redo [STEPS]
Arguments:
-
<STEPS>— Number of steps to redoDefault value:
1
fotobuch project
Project management commands
Usage: fotobuch project <COMMAND>
Subcommands:
new— Create a new photobook projectlist— List all photobook projectsswitch— Switch to another photobook project
fotobuch project new
Create a new photobook project
Usage: fotobuch project new [OPTIONS] --width <WIDTH> --height <HEIGHT> <NAME>
Arguments:
<NAME>— Project name
Options:
-
--width <WIDTH>— Page width in millimeters -
--height <HEIGHT>— Page height in millimeters -
--bleed <BLEED>— Bleed margin in millimetersDefault value:
3 -
--parent-dir <PARENT_DIR>— Parent directory where project will be created (default: current directory) -
--quiet— Suppress welcome messageDefault value:
false -
--with-cover— Create project with an active cover pageDefault value:
false -
--cover-width <COVER_WIDTH>— Cover width in millimeters (defaults to page_width * 2 if –with-cover is set, with warning) -
--cover-height <COVER_HEIGHT>— Cover height in millimeters (defaults to page_height if –with-cover is set, with warning) -
--spine-grow-per-10-pages-mm <SPINE_GROW_PER_10_PAGES_MM>— Spine width growth per 10 inner pages in mm (auto mode, conflicts with –spine-mm) -
--spine-mm <SPINE_MM>— Fixed spine width in mm (conflicts with –spine-grow-per-10-pages-mm) -
--margin-mm <MARGIN_MM>— Inner margin in millimeters (default: 0)Default value:
0
fotobuch project list
List all photobook projects
Usage: fotobuch project list
fotobuch project switch
Switch to another photobook project
Usage: fotobuch project switch <NAME>
Arguments:
<NAME>— Project name to switch to
fotobuch init
Create a new photobook project (alias for project new)
Usage: fotobuch init [OPTIONS] --width <WIDTH> --height <HEIGHT> <NAME>
Arguments:
<NAME>— Project name
Options:
-
--width <WIDTH>— Page width in millimeters -
--height <HEIGHT>— Page height in millimeters -
--bleed <BLEED>— Bleed margin in millimetersDefault value:
3 -
--parent-dir <PARENT_DIR>— Parent directory where project will be created (default: current directory) -
--quiet— Suppress welcome messageDefault value:
false -
--with-cover— Create project with an active cover pageDefault value:
false -
--cover-width <COVER_WIDTH>— Cover width in millimeters -
--cover-height <COVER_HEIGHT>— Cover height in millimeters -
--spine-grow-per-10-pages-mm <SPINE_GROW_PER_10_PAGES_MM>— Spine width growth per 10 inner pages in mm -
--spine-mm <SPINE_MM>— Fixed spine width in mm -
--margin-mm <MARGIN_MM>— Inner margin in millimeters (default: 0)Default value:
0
fotobuch completions
Print shell completion script to stdout
Usage: fotobuch completions –shell bash >> ~/.bash_completion fotobuch completions –shell zsh >> ~/.zshrc fotobuch completions –shell fish > ~/.config/fish/completions/fotobuch.fish fotobuch completions –shell powershell >> $PROFILE
Usage: fotobuch completions --shell <SHELL>
Options:
-
--shell <SHELL>— Shell to generate completions forPossible values:
bash,elvish,fish,powershell,zsh
This document was generated automatically by
clap-markdown.
Glossary
Domain-specific terms used throughout fotobuch. This is the authoritative definition source — all code, documentation, and communication should use these terms consistently.
Data and Storage
| Term | Definition |
|---|---|
| Vault | A folder on disk that holds one or more projects as a single git repository. |
| Project | A single photo book — one YAML file (photo list, layout, configuration) plus a Typst template — stored alongside other projects in a vault. |
| Template | The Typst file that defines the visual design of a project — page size, fonts, spacing, and how slots are rendered in the PDF. |
| Photo | A single image file imported into a project, belonging to exactly one photo group. |
| Photo Group | A named collection of photos, typically corresponding to a source folder. |
| Photo Weight | A numeric value on a photo that controls how much space the layout gives it relative to other photos on the same page. |
| History | The complete record of all changes to a project — stored as git commits, shared between GUI and CLI, and the basis for undo and redo. |
Layout
| Term | Definition |
|---|---|
| Page | A single double-sided spread holding one or more slots, each spread carrying its own page mode. |
| Cover | The first page (index 0) of a project, which may use a different size or layout than the inner pages. |
| Slot | A positioned, sized rectangle on a page that holds exactly one photo. |
| Aspect Ratio | The width-to-height ratio of a photo or slot. |
| Page Mode | A per-page flag: Auto lets fotobuch recalculate the slot arrangement freely; Manual locks slot positions so they are not changed during rebuild. |
| Bleed | Extra image area printed beyond the trim line, ensuring no white border appears after cutting. |
| Margin | White space kept between the content area and the page edge (inside the trim line). |
| DPI | Dots per inch — the print resolution of a rendered page in the release build. |
GUI Areas
| Term | Definition |
|---|---|
| Toolbar | The horizontal bar at the top of the window containing buttons for all main actions. |
| Photo Pool | The panel on the left side of the window listing all imported photos available for placement. |
| Central Panel | The main canvas area in the centre of the window where pages are displayed and edited. |
| HUD | The overlay controls that appear below a page in the central panel when the pointer hovers over it — includes a rebuild button, mode toggle, and delete button. |
| New Page Area | A drop zone shown in the central panel between pages where photos can be dropped to create a new page at that position. |
| Nav Bar | The panel on the right side of the window showing miniature thumbnails of all pages for quick navigation and selection. |
| Status Bar | The bar at the bottom of the window showing the current operation state and progress messages. |
| Thumbnail | A small preview image of a page or photo, shown in the nav bar and photo pool. |
| Zoom | A scaling factor applied to the central panel view that changes how large pages appear on screen without affecting the actual layout. |
Actions
| Term | Definition |
|---|---|
| Photo Add | Importing one or more image files from disk into the photo pool of the current project. |
| Photo Place | Assigning selected photos to slots on existing pages by timestamp (use rebuild first to create the pages). |
| Unplace | Removing a photo from its slot, returning it to the photo pool as unplaced. |
| Slot Swap | Exchanging the photos in two slots; blocked within one page when their aspect ratios differ. |
| Slot Move | Relocating a photo from one slot to a slot on a different page, or to a Manual-mode slot at an arbitrary position. |
| Dragging | Moving a photo with the mouse — left-drag from the photo pool to place, right-drag a slot in the central panel to swap or move. |
| Rebuild | Recalculating the page layout — targeted (only the selected pages, keeping photo assignments) or full (redistributing all photos from scratch). |
| Undo / Redo | Navigating backwards or forwards through the history of a project, reverting or re-applying changes one step at a time. |
| Selection | A set of pages or photos currently marked for the next action (rebuild, place, delete, etc.). |
| Multiselection | Selecting more than one page or photo at once, for example with Ctrl+Click or Shift+Click. |
Output
| Term | Definition |
|---|---|
| Preview | A fast, screen-resolution render of a page shown in the central panel and nav bar while working. |
| Release Build | A full print-quality PDF export of the complete photo book, saved as {project-name}_final.pdf in the project folder. |