mess · changelog
The working log, newest first. Back to the site.
Running log of updates, newest first. Each "## vX.Y" milestone is a build
that shipped (the site download / friends); "Unreleased" is what only
Eryk's installed app has. share-build.sh syncs the app version from the
newest vX.Y here.
Unreleased (in Eryk's installed app, not in the shared zip)
2026-09-07
- A crop you can walk away from. The crop editor has a Cancel button beside Done, and Esc does the same: the photo goes back to exactly how it was when you started, rotation included. Enter keeps the crop. The buttons say their keys.
- Demo hops moved to H. M was margin on the table and hops in the demo. It is margin everywhere now; H flips the demo between flat slides and hops, and the strip and cheatsheet say so.
- The toolbar says what you selected. Next to the zoom, a small readout says "3 photos · 1 slide". The arrange tools keep appearing only when the selection can use them.
- Right-click a table. In the sidebar's Tables list, right-click a row for Open, Rename, Duplicate, Archive and Delete. The icons that appeared on hover are gone. Double-click a name to rename it in place. Duplicate makes "<name> copy" with the same photos; nothing is copied on disk but the table itself.
- The demo names its keys. When D starts it, a strip at the top shows for a few seconds: arrows for speed and framing, M for hops, space to pull back, any other key stops.
- "names" in the Photos header. The Aa button now says what it does, and its tooltip explains that the list follows the stacking order on the table and that dragging a row restacks.
- The sidebar section is "Carousels". It lists carousels, so it says so, with their count, and it has a + like the Tables section to make a new one. It stays visible on a table with no carousel yet, with a hint, so the + is always there.
- Quieter, clearer messages. Snap, Margin and Gaps no longer toast "on" and "off": the toolbar button already shows it. Errors read in plain words, without the raw exception in the middle. When an error went by while you were not looking, the ? in the corner turns into a red !; click it to read the last few, then clear them. Right-click the ? for the list any time.
- Undo says what it undid. ⌘Z and ⇧⌘Z show a short line, "Undid the move", "Redid the crop to slide", so a run of undos is never a guess.
- The right-click menu has an order. Mark, then the photo (crop, border, Finder), then on the slide (fill, fit, crop to slide), then arrange (pile here, compare, front, back), then export and lock, then delete. Every time, in that order, with a hairline between groups. "Gather here" is now "Pile here".
- New carousel: two questions, not three. The dialog asks for the number of slides and the ratio, both remembered from last time, and names the carousel post-N itself. Rename it in the inspector.
- Crop to slide. Right-click a photo that hangs over the edge of its slide and Crop to slide trims the part outside, keeping the pixels inside exactly where they are. Works on several photos at once; a photo already inside its slide says so.
- A leaner toolbar. The + Carousel and Export… buttons are gone from the top: F and the File menu make a carousel, ⌘E and File > Export… export. The tiny clear-marks arrow is now a "Clear marks" button you can read.
v0.9 · 2026-09-07 · one place for everything
2026-09-07
- The sidebar is easy to resize. The grab strip on its right edge was six pixels wide and scrolled away with the list, so it was only there at the top. It now sits on the edge itself, ten pixels wide, shows a blue line while you hover or drag, and a double-click puts the sidebar back to its default width.
- The ratio belongs to the carousel. Carousel… from the sidebar opens the one place to change it, and every slide of the carousel takes it (frozen slides keep theirs). The ratio chips are gone from the toolbar and from the slide's own inspector.
- One Storage window. Storage… in the mess menu now holds everything about disk space: the usage bars, every table with what it weighs and what archiving it would free ("Archive, free 1.2 GB"), the archived shelf with Open and Unarchive, the trash with Restore and Empty, and the cleanup of photos no table uses any more. "Archived Tables…" and "Clean Unused Assets…" are gone from the menu; they live in that window. The archive and delete prompts, wherever you start them, say the same thing and the archive one names the number it frees. Every list lines up in columns, every section folds and remembers it, and the cleanup says what it does: photos are stored once and shared by every table, cleanup removes the ones no table uses any more, trash and archived tables included, and it cannot be undone.
- Import from a menu, and cull with the mouse. File > Import Photos… (⌘O) and Import Folder… (⇧⌘O) bring photos in without a Finder window beside the app; they land in the middle of the view, laid out like a drop. An empty table now offers an Import button and says that pasting works too. Right-click one or more photos and Pick, Reject and Unmark are there with their keys, so culling no longer needs the keyboard; the lightbox buttons show P and X.
- One set of words. The toolbar button is "+ Carousel", the sidebar section is "Slides", the slide menu says "Slide…" and the carousel menu "Carousel…". The photo border is "Border…" (it was "Photo frame…"), and photos "Fill slide" or "Fit in slide". The sidebar's culling groups are Picked, Unsorted, Rejected, and the cheatsheet leads with P, X and U. Deleting a table moves it "to the trash". The word frame is gone from everything you read; slides are slides.
- One inspector for a slide. Click a slide's badge, or pick Slide… from its sidebar menu, and one panel holds everything about it: label, which carousel it belongs to (a list, or a new name), background with the colors sampled from its photos, lock, freeze, move earlier or later, add a slide after, delete. Carousel… from the carousel's menu opens the same panel for the whole carousel: name, shared background, lock. The old badge popover and the separate carousel settings panel are gone, and so is typing a slide's position as a number: use the arrows, or drag it in the sidebar.
- Watermark presets. The watermark editor keeps named setups, each with its own logo, position, size and opacity: "IG corner", "client logo, big, centred". New, duplicate, rename (double-click the name) and delete live in the editor; the export sheet's watermark row shows them as chips next to Off, so switching logos between exports is one click. Your existing setup became the first preset.
- The export sheet, redone. What you export is a list down the left (selected photos, picked photos, slides, carousel strip, whole table, each with its count), and the right side is titled sections instead of rows of small chips: carousel, format, size, watermark, filenames, folder. Two new things for photos: a size, Original, 2048 px or 1080 px on the long edge, with a JPEG quality slider whenever a photo is re-encoded (a cap or a watermark), for web-size deliveries; and filenames, the original names or a prefix and a counter like guillaume-01.jpg, with the prefix remembered per table. Slides can take a custom stem the same way. The filename line shows the result as you type. (An image preview panel lived on the sheet for an hour and came out again: not needed.)
- One export sheet. Exporting used to live in seven places with four different sets of options: ⌘E exported straight away without asking, the toolbar had a five-item menu, the Export window had its own scopes, and the sidebar and right-click menus each had their own subset. Now every one of them opens the same sheet, set to what you had in hand: the photos you selected, your picks, the slides of a carousel, one carousel as a strip, or the whole table. Format and size are remembered per kind of export, not app-wide. The folder is remembered with the table and shown on the sheet, so you are not asked for it on every run; the sheet lists the filenames it is about to write, and if a file already exists it asks once: replace it, or keep both with a number. After an export the toast has a Reveal button. ⌥⌘E exports again with the same settings and folder, no sheet, for the nudge-and-re-export loop. The watermark editor is one click from the sheet's photos row. The words are the same everywhere now: photos, slides, carousel, strip, table.
- **The photo list scrolls smoothly on big tables, and thumbs stop popping in.** On a 3600-photo table, scrolling the sidebar's photo grid dropped to 1 to 4 frames a second for as long as you scrolled (Eryk's log: 13 seconds of it), and each thumbnail only started loading once it was already on screen. The grid was a CSS column layout of every photo on the table, and every tile that scrolled in made the whole thing re-flow. The grid now computes its layout from the photos' shapes up front, so nothing re-flows, and only the tiles within a screen of the visible part exist at all. Thumbs a screen ahead load before you get to them. Drag-to-reorder and selection rings work as before.
- New carousels start folded in the sidebar. Creating a carousel from the Frames dialog no longer drops eight "4:5 n" rows into the list; the group arrives folded and opens when you want it. Carousels you already have keep their fold state. The fold arrow on a carousel row is now a proper chevron, big enough to read as one, pointing down when the slides are shown and right when they are hidden.
- A landing drop cannot be cut short. While photos from a drop are still arriving, quitting, closing the window, deleting the open table and Asset cleanup now wait, the same way switching tables already did, and say how many photos are left. Before, a quit mid-drop silently left the rest off the table, and a cleanup mid-drop could sweep photos that were on disk but not yet placed.
2026-09-06
- Photos keep up with the drag. Moving and resizing photos, and sweeping a selection, no longer queue the photo preview one display frame behind its outline. Both now paint in the same frame.
2026-09-05
- Less repeated work on big tables. Close-up views skip distant photos when preparing the scene. The renderer reuses matching GPU settings, and switching tables cancels photo loads left behind by the previous table. Image quality and stacking stay the same.
- Unsaved work stays on the table. If saving fails, switching or creating a table, deleting the open table and cleaning up assets stop until the last change has been saved. Keyboard navigation in the table switcher keeps the highlighted row visible after the list changes.
- Undo removes the whole import. ⌘Z after dropping a folder used to take back one photo at a time. It now takes back the whole drop in one step, tidy pass included. If you moved something while the import was still landing, that move stays its own step and the import undoes around it.
- Export photos with a watermark. The Export dialog has a new "Selected photos" scope: the full-res files of the photos you selected go to a folder, and a watermark switch there composites your logo onto each one. "Set up…" opens the watermark window: choose a logo (PNG with transparency, JPEG, WebP or SVG), pick one of nine positions, set drag it exactly where you want on a big live preview (or use the horizontal and vertical sliders, or one of nine quick spots), set its size and opacity, and flip through your selected photos with the arrows to see how it sits on each. The logo and the settings are remembered. Watermarked files come out as JPEG (PNGs stay PNG) and are re-encoded, so camera metadata is dropped; with the switch off you still get the untouched originals. Clips are copied as they are. The right-click "Export photos to folder" uses the same switch and says so in its label.
2026-09-04
- Quieter effects. Snap lines, gap lines, gap pills and the margin gutter are all white on gray now, no more pink. The gap pills also shrink with the photos once you zoom out, instead of staying full size and crowding a small pile. Selection stays blue.
- You can see which photos are selected. Shift-clicking or cmd-clicking several photos used to draw one big box around them all and nothing on the photos themselves. Each selected photo now keeps the blue tint and hairline ring the marquee already showed while sweeping, so a selection inside a pile reads at a glance. A single selected photo looks as before.
- Margin gets its own number and a quieter look. A px box appears next to the Margin button while it is on, separate from the Pack and Stack gap, so the two never move together. The gutter that lights up when a photo lands on its margin is now white on gray instead of pink: pink stays for edges you hit, gray is for spacing you set.
- Alignment lines stop pointing at photos you can't see. The magnet used to consider every photo on the table, so an edge could snap to something far off screen and the guide line ran across the whole screen toward nothing. Now only what is on screen when the drag starts can pull an edge (zoom out to align with something far away), and the guide is a short line joining your photo to the one it lined up with, so you see what you aligned to. Same for frames.
2026-09-02
- Margin: photos keep a gutter, like padding. A third toggle next to Snap and Gaps (key M). With it on, push a photo against another one, or against a slide's edge, and it stops the gap field's distance away instead of touching: anywhere from a slight overlap to just past the gap lands on the gap, so a mosaic falls into place without aiming. Resizing an edge or corner toward a neighbour does the same. Edges still line up flush with each other. The number is the one Pack and Stack use, shown on the button while it is on, and the pink gap pills confirm it. Off (the default) leaves Snap exactly as it was. (The first build only caught the gutter within a few pixels of an invisible target, which in practice never happened; this is the fix.) And you see it happen: the moment a photo lands on its margin, the gutter between the two edges fills with the pink snap tint and shows the px in the middle, so a mosaic reads its spacing while you build it. A gutter only counts against a real neighbour (one the photo actually sits beside or above), never against a photo off to the side; lining edges up flush across a distance still works.
- A whole-app review, fixed in one pass. Four reviewers read every file; the confirmed findings below were fixed by four more, then re-verified. 36 new tests (the store, autosave and migration had none), 219 in total, Rust at 22, clippy clean.
- The last edit before a switch or quit can no longer vanish. The autosave cleared its "unsaved" flag the moment a write started, so a table switch or ⌘Q landing during that write saw nothing to flush and moved on, dropping any edit made while the write was in the air (or quitting mid-write). Flush now waits for the running write and then writes again if anything changed meanwhile. Deleting the open table flushes first too, so the trashed copy is current and the old "Save failed" toast that followed a delete is gone.
- Archive keeps its promises. Two holes: re-dropping the same files onto an archived table wrote nothing (the vault saw a known photo and stopped), so "get originals back by re-importing" was false; and photos small enough to be their own preview (2048px or under) had their only file deleted, going blank on the table and in exports. Re-import now restores a released original, and archive leaves those small files alone; the confirm text says so.
- Clean Unused Assets waits for the save. The menu item ran straight in Rust, so a photo pasted seconds earlier could be swept before the table referencing it was written. It now flushes first, like every other menu action.
- Switching tables mid-import is refused. Photos still importing landed on whichever table was open when each one finished. A drop now holds the table until it is done, with a toast saying how many are left.
- A video clip no longer breaks slide export. A missing await let the decode failure skip the poster fallback and fail the whole slide. Also: carousel names with double dots exported nothing (the filename guard refused them); they are cleaned up first now.
- Inserting a slide carries the photos with it. "Add slide after" shifted the later slides but not the photos on them, undoing a frozen slide's pinned composition in one click. It now moves each slide's photos with it, the same rule the reorder uses.
- Pasted slides get their own number. ⌘C/⌘V on a slide produced a twin with the same slide number, frozen or locked if the original was, and stacked among the notes. Copies now take the next free number in their carousel, thaw, unlock, and land in the frame band.
- Renaming a carousel onto an existing name is refused with a toast, instead of silently merging two decks with duplicate slide numbers.
- Photos stop sticking at preview quality after a zoom. When the last frame of a scroll-zoom crossed the reveal ring, the "camera at rest" timer was cancelled and never re-armed: the sharp tier never loaded and keeper glow stayed off until the next click. Same for pinch-end. The selection box also stopped flicking sideways for one frame on long pans.
- A drag survives losing the window. ⌘-Tab, or the delete confirm popping up mid-drag, used to strand the gesture: the next click was swallowed and its release committed the stale drag wherever you were. Focus loss now rolls the preview back cleanly; Space no longer sticks as a pan modifier either.
- Drags cost one frame of work, not one per mouse report. Item drag and resize now coalesce to the display refresh like the marquee already did, and snap targets are gathered once per gesture instead of on every event. The photo layer stops re-sorting every item every frame.
- Dialogs own the keyboard while open. With the Export dialog, Keyboard Shortcuts, Storage or the table switcher up, Escape cleared the selection behind it, Enter opened the lightbox on top, N dropped a note, D started the demo. One shared hook now takes the keys for any open overlay (⌘ chords still reach the menu), and ⌘K over the lightbox now shows the switcher above it instead of typing into the lightbox. A lightbox or compare view left over from another table closes itself instead of leaving the keyboard dead.
- Small things. New-table thumbnails appear after the first save instead of after a restart; the sidebar's slide freeze glyph is a snowflake so it reads differently from the deck padlock; the shortcut sheet matches what the keys do; empty-table copy no longer promises a double-click note; the window-drag strip no longer sits over dialog backdrops; a hand-fixed board.json without a schemaVersion opens; typing "?" in a note no longer opens the shortcut sheet; dialogs carry proper dialog roles; package and Cargo versions match the app (0.8.0); every em dash left in UI copy, README and site text is gone.
v0.8 · 2026-09-01 · the control batch
Rebuilt from 4a03d90, at mess.eryk.be/download/mess.zip. New since
v0.7: measuring and control. Gap readouts between photos and slide
edges (G), Center and Spread on slides, one Export dialog with PDF
everywhere, OG resolution and per-carousel scoping, right-click menus
for slides and carousels in the sidebar, carousel and frame settings
panels, the two-tier lock system (carousel lock, slide freeze with
photo pinning), smarter slide reordering that never strands a photo,
frame chrome that stays calm during fast zooms, cmd-click on the
canvas, corner-resize alignment guides, and a recovery flow when
macOS blocks the vault folder.
2026-09-01
- Slide badges stop towering over distant frames. The "post-1 · 1" chips kept one screen size at any zoom, so a zoomed-out table was mostly badges. They now shrink with their frame once zoomed out (about 2% of the frame's width), and up close they cap at their classic size instead of growing huge.
- Frame chrome behaves during fast zooms. Two artifacts fixed: slide border lines used to balloon into fat grey bars mid-zoom (their thickness only re-adjusted once the camera settled) - they now cap the same way the badges do, staying thin near and proportional far. And the darkening around a selected slide no longer lags a quick zoom-out, revealing an undimmed ring at the edges: the veil now extends far past the screen.
- A denied Documents permission no longer bricks the app. Clicking "Don't Allow" on macOS's Documents prompt used to kill the launch silently, and macOS never asks again on its own. Now the app starts anyway, explains what's blocked, and offers "Open System Settings" (straight to the Files and Folders pane) and "Relaunch mess" on every launch until access works. Relaunch, not retry: macOS holds a permission denial for the life of the process, so only a fresh launch can pick up the new grant; the button does the restart for you and your tables come right back. macOS can also block the folder silently, without an error or a prompt; the boot now times out after six seconds and shows the same recovery, and if a late permission prompt does appear and gets an Allow, the dialog dismisses itself and the tables load.
- Two locks: carousel lock and slide freeze. The carousel header's padlock locks the deck in place: no dragging, nudging, or resizing (the canvas right-click has the same toggle). The padlock on a slide ROW is stronger - freeze: that slide ignores accidents - carousel repaints, ratio sweeps, direct reorder - PINS the photos sitting on it (they refuse drags, nudges, and the arrange tools, though they still ride along when a sibling reorder displaces their slide), and anchors its deck against drags. Deliberately opening that slide's own settings still edits it normally: freeze guards against accidents, not intent. The canvas badge shows the little lock only for frozen slides, not for a locked carousel. Frozen slides can still be displaced when a sibling reorders past them (a strip has no other option), carousel renames still include them (a split deck is worse), and delete keeps its confirm. Both padlocks are quiet line-drawn glyphs in the archive-button style, dimmed, visible without hover once active; the frame badge shows a small lock for either.
- Photos overhanging a slide edge now travel when slides reorder. Swapping slide order moves each slide's photos with it, but two things stranded them: the old rule required a photo to be 100% inside the frame, and a multi-position drag walked one swap at a time, re-deciding ownership halfway through (a photo could hop once and get left behind while its slide went on). Now the slide holding most of a photo's area owns it, ownership is decided once from the layout as you arranged it, and the whole reorder lands (and undoes) as one step. Big pictures work too: a photo larger than its slide (even one covering the whole frame as a backdrop) belongs to it and travels, and a sloppy overhang into the neighbour no longer counts as seam content. Only photos claiming comparable chunks of two slides (a genuine panorama across the seam) stay put.
- Gaps are visible now, and measurable. Select photos and thin pink lines span the gaps between neighbours, each with a small px pill at its middle, the same unit as the toolbar's gap input. Slide edges count too: a photo on a frame measures to the frame edge on any side with nothing in between, so margins read at a glance. The readouts only appear up close, once a photo spans about 48px on screen; zoomed out they would bury the pictures they measure. Off by default: measuring is a mode you enter with the Gaps button next to Snap or the G key, and the choice sticks. Skips selections above 30 photos.
- Arranging on a slide: Center and Spread. With photos selected over a frame, two new toolbar buttons work relative to that slide. Center moves the group to the slide's middle, keeping its own layout. Spread distributes the photos across the slide with equal gaps and equal margins to its edges.
- **One Export dialog: every target, every format, plus OG resolution.** Export opens a small dialog: what (slides, carousel strip, whole table), format (PNG, JPEG, PDF for all three), and resolution (1x, 2x, or OG) in one place, instead of a menu of pre-baked combinations. Slides as PDF means one file, a page per slide in deck order; strip and table PDFs are single pages. OG scales each slide until its sharpest photo exports at native pixels (8K cap), and raises the whole-table size cap to 16K. With more than one carousel on the table the dialog adds a carousel row (All, or one deck; the strip always wants exactly one). The quick paths are untouched: the menu keeps one-click PNG slides, originals, and copy-to-clipboard.
- Right-click slides and carousels in the sidebar. Slide rows under Frames carry a menu: export this slide, copy it to the clipboard, show it on the table, or delete it. The carousel header ("post-1") gets its own: export that deck's slides as PNGs, as a PDF, or as one strip, and show the whole deck on the table, so a table holding several carousels exports each one cleanly.
- Cmd-click works on the canvas. Clicking a photo with the command key held toggles it in the selection, exactly like the sidebar always did; cmd-drag on empty canvas keeps the selection additive like shift. One habit, both places.
- The sidebar's delete and archive buttons are easier to hit. They still appear on hover, but larger and brighter, instead of the faint little glyphs they were.
- Alignment lines now show when corner-resizing photos. Resizing by a corner never snapped or drew a guide against horizontal edges, so "resize until it matches the neighbour's height" silently missed. The snap now lands on whichever nearby edge is closer, vertical or horizontal, and draws its pink guide, with the other side following the photo's aspect ratio.
2026-08-28
- Buy Me a Coffee in the Help menu. One item, opens buymeacoffee.com/eryksienicki in the browser. The site's download section links the same page.
- Frame labels no longer haunt the next table. Switching tables could leave the previous table's frame labels (post-1 · 1 and friends) floating over the new one, gliding along with the camera. The layer that holds notes and frames is a composited layer, and when a switch emptied it while only its position kept changing, macOS's webview kept showing the layer's old picture. That layer is now dropped and rebuilt for one frame on every table switch.
v0.7 · 2026-08-28 · what the site serves
Rebuilt from 89ab531, at mess.eryk.be/download/mess.zip. New since
v0.6: the smoothness batch (clicks select instantly, drags start
without a stutter, drag-select frames down from 350ms to 21ms, and
selection staying cheap on multi-thousand-photo tables), honest
sidebar counts, recursive folder drops that skip duplicate files by
content, and the 2026-08-26 sorting refinements (filename-order
lightbox and gather, Space previews the selection, shift-click range
select, the reworked compare layouts).
2026-08-27
- Clicking a photo selects instantly. The click's ring flip on the photo's sidebar tile made the browser repaint a big slice of the thumbnail masonry, and the whole frame (selection box included) waited for it. Off-screen sidebar tiles now skip layout and paint entirely (content-visibility), and the sidebar's ring update itself waits one frame - the canvas answers the click first, the sidebar catches up imperceptibly later.
- Grabbing photos no longer stutters at the start. Picking up a selection raises it to the top of the pile, and the sidebar list is ordered by exactly that - so the whole thumbnail masonry rebuilt itself right as the drag began. The sidebar now freezes its view while a gesture is live and catches up once, on release.
- Drag-select without the lag. Several rounds of profiling the live app during real laggy drags (3-5 fps at worst). Round one: thousands of per-photo watchers (every canvas box and sidebar row asking "am I selected?") added up to ~25ms per marquee move; one watcher now flips the highlight directly on the affected elements. Round two, caught by an in-app frame recorder: the input handlers asked the browser for the canvas position and size on every mouse movement, which forced the engine to re-lay-out the whole interface each time (those reads are cached now, refreshed only when the window or sidebar actually resizes, and the marquee runs at most once per screen frame). And the decisive pair: the sweep wrote the selection to the store on every change, and its ring flips forced the image-stuffed sidebar to repaint every frame - a constant ~350ms. The sweep now draws its live highlight on the WebGL photo layer, which redraws per frame anyway, and the store, toolbar, and sidebar learn the selection once, on release. Frame times measured in the live app: 350ms before, 21ms after. The highlight itself is subtle: a faint blue tint, plus a hairline ring only on photos big enough on screen to carry one - zoomed way out, the tint alone marks the catch instead of a wall of blue boxes.
- Sidebar counts stay honest. Each table's photo count in the sidebar now updates with every save instead of freezing at whatever it was when the app started.
- Folder drops: everything inside, each photo once. A dropped folder now brings in every photo anywhere inside it, subfolders included (hidden files and symlinks still skipped), in natural filename order; drops of more than 200 photos ask first, so a stray drop of a whole archive can't flood the table. Recursive trees often hold the same photo several times (roll folders, curated copies) - each distinct file lands once, by content, with a note saying how many duplicates were skipped. And while a big import is still landing, the provisional grid leaves room for portrait photos instead of stacking them on the next row.
2026-08-26
- The lightbox walks in filename order. Left/right arrows follow the filenames (numbers compared by value, so -2 comes before -10), the same order imports land in - not the photos' positions on the table.
- Space previews what you mean. With several photos selected, Space opens the lightbox on just those; with one selected it starts there and walks the whole table; with nothing selected, a tap of Space previews the whole table from the first filename. Holding Space to pan still works - the preview only opens if the hold wasn't used for a pan.
- Shift-click selects the run between. Click one photo, shift-click another: everything between them joins the selection - along a row, down a column, or the whole block in a grid.
- Gather here piles in filename order. The gathered grid reads like an import (alphabetical), not like wherever the photos happened to sit.
- Quieter flag marks. The lightbox's "pick / reject" badge and the compare view's little green/red circles are gone - the highlighted Pick/Reject button already tells the story.
- Compare view: pick your layout, no more dead space. A small switcher above the photos chooses between one row and 2x2 (for four shots). Cells now hug each photo's real width, so portrait shots sit next to each other instead of centered in window-wide columns. In 2x2 the filename and Pick/Reject move beside each photo (left column on the left, right column on the right), giving the photos the full row height.
v0.6 · 2026-08-25 night
New since v0.5: releases are numbered and browsable.
2026-08-25
- What's New. The mess menu opens the changelog inside the app, with each release folding under its version number; the site serves the same log at /changelog (unlinked, direct address only).
- Version numbers. Builds are versioned (this is v0.6); the build script stamps the app from the newest release entry so the download, the About box and this list always agree.
v0.5 · 2026-08-25 evening
Rebuilt from a6b42c5, at mess.eryk.be/download/mess.zip. New since
the afternoon share: a full menu bar (File / View / Help with the
"Show ? on the Table" toggle), window dragging finally works (the
start-dragging permission was never granted), classic traffic-light
placement, the ? pill, demo defaults (flat, 4x), and Gather-here's
flying animation.
2026-08-25
- A full menu bar. File (New Table, Switch Table…, Export…, Copy Slide as Image), View (Fit Table / Selection, Zoom to 100%, Start Demo, Toggle Sidebar / Toolbar) and Help (Keyboard Shortcuts, a "Show ? on the Table" toggle that hides the floating ? pill but keeps the sheet reachable from the menu, and the mess website). The storage items stay in the mess menu.
- A real titlebar. A classic 40px bar across the top with the traffic lights and the table's name in it; grab it anywhere to move the window. The sidebar, toolbar and canvas start below it. Hidden in demo mode.
- The shortcut sheet is easier to find: "Keyboard Shortcuts" in the mess menu (⇧/) and a small ? button in the bottom-right corner, on top of the ? key. Demo has its own section in the sheet, and the window's traffic lights sit in a classic-height titlebar band that is draggable along the whole top edge.
- Demo mode defaults to flat slides at 4× speed; M lifts them into hops, arrows still adjust pace and framing. M has its own line in the cheatsheet now.
v0.4 · 2026-08-25 · what friends and the site had
Rebuilt from ed6f383, served at mess.eryk.be/download/mess.zip (zip
contains mess.app + READ-ME-FIRST.txt). New since the previous share:
Gather-here photos fly into the pile, the demo-mode polish (hops, M,
speed/zoom keys, directional motion trail, fisheye), the lightbox info
panel (I), quieter selection handles, and all of the 2026-08-21 fixes
below.
v0.3 · 2026-08-21 afternoon
Rebuilt from dbe7ad2 (everything below through 2026-08-21). Apple
Silicon only, ad-hoc signed, Desktop/mess-share/mess.zip +
READ-ME-FIRST.txt. Highlights of this share: photos rendered by the
GPU (smooth at every zoom, no more far-out lag, memory under control),
demo mode (D) with hops, motion trail and live controls, the I info
panel in the lightbox, quieter selection (handles on hover, T pins),
sidebar multi-select, boards renamed to tables, and the site rewritten
around the table with a tl;dr.
2026-08-21
- App: file info in the full-screen view. Press I (or the ⓘ button) while looking at a photo and a panel lists what the original file knows: dimensions and size, when it was taken, camera, lens, focal length, aperture, shutter, ISO, colour profile, software, GPS if any, duration and codecs for clips, plus the crop, rotation and mark on the table. Read through macOS Spotlight, so no new dependency. The panel stays open as you browse with the arrows.
- App: the ▶ badge on video clips is back. It had slipped under the new graphics layer. It is now drawn by that layer, at a fixed size whatever the zoom, and disappears on clips too small to carry it. Playing a clip (open it full screen) never changed.
- App: keeper glow is back, and stays on while you move. The first GPU build drew keepers with a thin hard ring that read as a grid of boxes at overview and vanished during scrolling. Keepers now carry a soft halo sized to the photo, drawn by the graphics card, visible at all times.
- App: clicking right after a scroll no longer throws the view back. A click within a fraction of a second after scrolling or zooming made the camera jump to where it was before the scroll. Fixed.
- App: quieter selection. The eight resize handles now appear only while the pointer is over the selected photo (or group), and T pins them on. The hairline outline stays. During a Z flight or a pinch the outline used to scale up into a fat white frame; the selection chrome now hides while the camera is zooming and returns the moment it lands.
- App: photos now render on the graphics card. The table's photos, slide backgrounds, reject dimming and keeper rings are drawn by a WebGL layer instead of hundreds of browser image elements. Nothing changes in how you work: clicking, dragging, marquee, crop, frames, notes, export are all the same. What changes is the ceiling: panning and zooming far out over a 500-photo table, which used to be the slow spot, costs the GPU a couple of milliseconds, and tiny photos stop shimmering thanks to mipmaps. Graphics memory has a hard budget so it cannot creep over a long session.
- App: demo mode. Press D and the table turns into a slideshow: the sidebar, toolbar, selection handles and cursor disappear, and every few seconds the camera flies to another photo, slowly, with the travel-then-dive move. It never picks one of the nearest photos, so each move crosses the table as a hop: the camera lifts off the photo while travelling, higher the farther it goes, and dives back down onto the next one (M switches to flat slides and back). It never crops into a photo. Hold Space to pull back and see the whole table for as long as you like; let go and it carries on. If two or more photos are selected it only cycles through those; otherwise every photo that is not rejected. ←/→ change the pace (half speed to 6×), ↑/↓ zoom in and out on the photos (from showing the table around each one to cropping into it), and a real motion blur follows the camera: a streak along the direction of travel for pans, a radial one for zooms, its length set by the speed that frame, nothing at takeoff and landing, plus a light fisheye warp that grows with speed and flattens as the camera lands. Drawn by the graphics card. Any other key or a click stops it. Nothing is changed on the table.
- App: stops hoarding full-size previews in memory. A profile of the "gets laggier the longer I move around" problem showed the Mac running out of memory mid-session and the browser engine throwing away and rebuilding everything, frame after frame. Two habits caused it: photos that had scrolled off screen kept their 2048px preview decoded (16MB each, for hundreds of photos), and the zoom-in pre-loading from this morning was too eager. Off-screen photos now fall back to the 512px preview, and pre-loading of the big version is limited to the dozen photos that are actually about to need it.
- App: ⌥⇧D opens Safari's Web Inspector (from the ⌥⇧P readout), so a slow stretch can be profiled properly instead of inferred from counters. No effect unless you press it.
- App: ⌥⇧P shows a performance readout and records it. A small box in the corner with frames per second, the worst frame, how many frames ran long, and how often the canvas re-rendered in the last half second. While it is on, every half second is appended as a line to
perf.login the vault folder (table name, zoom, fps, worst frame, long frames, commits, canvas renders, item count, moving or not), with every key press logged in between (not text typed into notes or fields), so you can roam a table and hand over the file. Turning it off shows where the log went. Off by default.
- App: rejected photos never load full resolution on the table. A reject is dimmed and out of the running, so it is now capped at the 512px preview no matter how far you zoom in; the 2048px decodes go only to photos still being judged. Rejecting a photo drops it to the preview at once, un-rejecting brings the sharp version back. The full-screen view is unchanged, so a reject can still be re-judged at full quality.
- "Boards" are now "tables", in the app and on the site. Sidebar header, ⌘K switcher, toolbar (Fit table, Rename table, Whole table export), cheatsheet, Storage and Archived dialogs, the app menu (Archived Tables…), toasts, the empty-state hint, the default name (Untitled table) and the whole-table export filename (
-table.png). Files on disk are unchanged: the folder is stillboards/and the document is stillboard.json, so existing vaults open as before.
- Site: the table is the product, the carousel is an extra. Hero, title, meta descriptions, the "How it works" third step, the features page intro, and the Canvas and Carousels section intros all now describe mess as a fast table for moving and sorting photos, with frames and 1080px export named as an optional tool on top. A new tl;dr section under the hero says the same in four plain paragraphs for someone who has never seen the app - written after a content review found the site never said the word Instagram or defined board, keeper, frame or carousel. CLAUDE.md's one-liner matches.
- App: sharp photos arrive sooner when you zoom in. Before, the higher-resolution version of a photo was only requested once the zoom had fully stopped, so it always popped in a beat late. Now, while you are still zooming in, the app quietly loads and decodes the version the photos on screen are about to need, so the swap at rest comes from memory. Capped at six loads at a time; zooming away drops the leftovers. And the swap itself no longer waits for you to stop: the moment a photo grows past the size its current preview can cover, the sharper version is put on screen while the zoom is still going.
- App: multi-select in the sidebar. Photo rows and tiles follow Finder conventions: click flies to the photo and selects it, ⌘-click adds or removes it from the selection without moving the camera, ⇧-click selects the run from the last clicked photo. Frames and notes accept ⌘-click too.
- Site: keyboard map redesigned. Grouped into Navigate / Culling / Create & edit / Arrange / Boards & files cards, key beside (or over) its meaning, no more orphaned wraps; canvas Z and lightbox Z spelled out separately.
v0.2 · 2026-08-21 morning
Rebuilt from bc7b832 (all of 2026-08-20 below). Apple Silicon only,
ad-hoc signed, Desktop/mess-share/mess.zip + READ-ME-FIRST.txt.
2026-08-20
- App: Z flies the camera, properly. Z zooms to fit: the selection when there is one, the whole board otherwise, and pressing Z again while sitting at the selection fit toggles back out to the full board (the lightbox keeps its own Z, the 1:1 zoom). The flight travels first and dives second: the camera center moves on the fast curve while the zoom holds back on an ease-in-out, so Z glides over the target and then plunges (520ms in, 420ms out, slowed from 260ms per Eryk's ask). And a Z pressed mid-flight now toggles to the other destination instead of restarting the same flight, which used to read as a dead key for a couple of seconds.
- App: flights at gesture smoothness. Measured with synthetic input and window recording on the 502-photo board: gestures held 40fps while Z and Cmd-0 flights dropped to 18fps with 200-400ms stalls. The causes, all fixed: Z first had to mount hundreds of culled offscreen photos (culling now starts at 1000 items, so all of Eryk's boards stay fully mounted); the resolution picker upgraded every photo to its 2048px variant at the keypress (only the dive target upgrades now, and the takeoff commit writes the destination camera, so photos mount at their final preview size straight from the warm cache); flights now strip motion decorations like gestures do and pre-mount their destination before the first frame; and mid-gesture reveal commits over-mount a larger ring, so React re-renders a couple of times per zoom-out instead of every few frames. After: worst flight gap 60-70ms, was 400ms.
- App: quieter selection chrome. Hairline border at 55% opacity with smaller, dimmer resize handles - and below 36px on screen the handles step aside entirely (they used to hide the photo), leaving just the hairline.
- Site: a real window on the homepage. A "Not a mockup" section between the hero animation and the claims: a live capture of the FE4 board (sidebar, toolbar, carousel strip), linking to the showcase. First a still, then an 8 second loop of the real window, re-recorded with the day's polish in frame (travel-then-dive Z flight, broken-white selection, no chop): Z dives into one selected photo, Z again pulls back to the full board. Recorded live via granted Accessibility access (synthetic Z keystrokes during screencapture -v).
- Site: one nav everywhere. Home / Features / Showcase with the active page highlighted; Get updates button removed.
- Site: homepage fix. Versioned asset URLs plus a
_headersfile so the 4 hour edge cache on mess.eryk.be can never pair new HTML with old CSS again. Hero lockup dropped (the header owns the name), brand-noun repetition in the copy toned down.
v0.1 · 2026-08-20
Baseline: rebranded "mess", Apple Silicon only, ad-hoc signed.
Everything up to and including the import ordering work
(f37cd50 Imports sort naturally).