Photo books
A photo book is a blueprint setting (blueprint.books): a cover, then pages that each lay out a few photos from a feed (the Gallery by default). The photos stay posts in their feed; a book only points at them, so a deleted photo simply drops out. Two general blocks show books, and the AI builds them with the same blueprint changes as anything else.
Code: convex/kits/photobook/ (lib, kits, blocks, books, guide), src/kits/photobook/, tests/photobook.test.ts. The starter is convex/lib/templates/photobook.ts.
The kit #
photo-book (group Build) includes the Gallery, adds one book (book, chapters by month) and a page (photo-book) with the book and a shelf. Taking the kit out takes /books with it (undo brings it back).
A book #
| Setting | What it does |
|---|---|
id, name | Short kebab-case id; the name people see |
feed | Where the photos come from (a /feeds id), default gallery |
tag | Only photos with this #tag: an album |
from, to | Only photos posted between these days (YYYY-MM-DD) |
shape | portrait (default), square or landscape |
cover | { title?, subtitle?, photo?: ref or "none", layout?: photo · framed · plain, tint? } |
fill | How it lays itself out: { order: old · new, perPage: mix · 1–4, chapters: none · month · day · tag, captions, max: 1–400 } |
pages | Hand-made pages. Unset: the book lays itself out from the photos and grows with them |
end | Words on the last page |
samples | [{ emoji, tint?, label? }]: a sample spread shown until the book has photos |
A page is { id, layout, photos?, title?, text?, date?, tint? }. Layouts: full (1), framed (1, with its caption), two (2 side by side), stack (2 one above the other), trio (1 big and 2 small), grid (4), words (none), chapter (a title or a date, with an optional photo behind it). A photo ref is "<post id>" or "<post id>#<n>" (the post's nth photo). tint is a style colour name (tint1…tint6, accent, paper), never a hex value.
Laying out (autoPages) is pure and stable: the same photos always make the same pages with the same ids. With perPage: "mix" a photo with words gets a framed page (at most every third page), two wide photos stack, two tall ones sit side by side, a wide one with two tall ones makes a trio, and every fifth page with four photos to go is a grid.
Limits: 24 books, 200 pages a book, 1200 placed photos in all. Big books should keep laying themselves out.
Blocks #
photobook.book{ book, view: flip · scroll, start: cover · first, thumbs, edit }: the cover, then pages you swipe through with a light page-turn tilt (off when the device asks for less motion), a page count and a strip of small pages. Tap a page to read it full screen. People who manage the space get Edit book.photobook.shelf{ title, books, albums, feed, columns, empty }: covers that open full screen. The space's books first, then (albums, default on) one book for every #tag of the feed, so each Gallery album is a book by itself.
Editing a book #
Edit book opens a sheet with the cover (title, words, photo, layout, paper), the shape and chapters, and every page as a small picture. Tap a page to change its layout, swap a photo (tap a slot), write a title or words, pick its paper, move it or remove it. "+" adds a page from up to four picked photos, with the layout that fits them. A book that lays itself out becomes hand-made the first time a page changes ("Arrange by hand"); "Lay out from photos again" goes back. Save is one blueprint change (blueprint.change), so it is one version with undo in History.
Server functions (convex/kits/photobook/books.ts) #
Every read names the block that shows the book; the server finds the block and checks the person can see it, so a book is exactly as visible as its page and block.
read({ block, book?, album?, upTo?, all? }): the cover, the page count and the firstupTopages with photo links (the app asks for more a few pages ahead).all(managers) adds every page with its refs, for editing. Gone photos leave an empty slot for managers and drop out for everyone else.photos({ feed?, tag?, before? })(manage): photos to pick, newest first, 48 posts at a time.shelf({ block }): the shelf's book covers and albums (tag, count, newest photo)._photoList(internal): what the AI'slist_photostool returns.
The AI #
The guide (kits part) explains books, layouts and refs. list_photos { feed?, tag?, limit? } (scope data.read, manage) returns each photo's ref, caption, #tags, shape (wide, tall, square) and date; captions are marked as data. "Make a book of #italy with a chapter for each day" is one proposal: { op: "add", path: "/books/-", value: { id: "italy", name: "Italy", tag: "italy", fill: { chapters: "day" } } } plus a page or shelf that shows it.
Words #
Every word is blueprint.words["book.<key>"] (keys in BOOK_WORDS, convex/kits/photobook/lib.ts).
The Photo book starter #
photobook in convex/lib/templates/photobook.ts, in the Album style (warm paper and ink, serif titles, terracotta and sunflower, charcoal and amber by night). Tabs: Book (the book that fills itself, then tiles: Add photos, Albums, Guestbook, New book), Photos (the Gallery grid), Albums (the shelf), Chats, Guestbook; HQ and the AI in the top bar. Kits: photo-book (with the Gallery), guestbook, direct-chat, group-chat, analytics. It is only blueprint data made of general blocks, so the AI can build the same thing in any space. Its picker card uses showcase.