Appearance
Retouch
Prov1.3.0An on-device image editor — crop, rotate, adjust and export
Retouch is a Pro app
It needs a free KimtOS account and a Pro subscription. Everything still runs on your device — Pro unlocks the app, it does not send your data anywhere. Install it without Pro and the app opens to an upgrade wall. See what Pro includes
Overview
Retouch is an image editor that runs entirely inside the browser tab. Open a photo or screenshot, crop and straighten it, adjust the colour, and export the result — without it ever leaving your machine. It is part of the kimtos new-tab app suite.
Everything is fully on-device. Retouch is built on the HTML5 Canvas and the browser's own image pipeline: there is no backend, no account, no network call, and — unlike the other media apps — no model or WASM download. It opens instantly the first time.
Highlights
- Open anything — pick a file, drag and drop it onto the window, or paste an image straight from the clipboard (
⌘/Ctrl+V). - Transform — rotate ±90°, flip horizontally or vertically, crop with a full editor (eight handles, drag-to-move, aspect presets, a rule-of-thirds grid and exact pixel dimensions), and resize to exact dimensions.
- Adjust — brightness, contrast, saturation, blur, grayscale, sepia and invert, with a live preview. "Apply" bakes the adjustments into the pixels; "Reset" drops them.
- Undo / redo — step back and forth through your edits, or reset all the way to the original image.
- Save your images — press Save and the image is kept in the sidebar, together with its pending adjustment sliders, so reopening it puts you back exactly where you left off. Right-click a saved image to Open, Rename, Download PNG or Delete it; Select (or drag across the rows) deletes several at once, with one confirm and one undo.
- Zoom — zoom in and out with the toolbar controls or
Ctrl/⌘+ scroll, and Fit to snap back to the window. A zoomed image scrolls inside the canvas area instead of being squeezed to fit. - Export — download as PNG or JPEG, or copy to the clipboard — which pairs neatly with the Clipboard app.
- Floating window — pop Retouch out into an always-on-top window and edit while you work in other tabs.
- Transparency-aware — a checkerboard backdrop, so transparent regions read clearly instead of blending into the page.
Privacy model
Retouch is the simplest privacy story in the suite: the image never goes anywhere.
- It is decoded into a canvas in the tab, edited in memory, and written back out when you export.
- Nothing is uploaded, and there are no analytics or third-party calls.
- Saved images stay on the device. They go into the same local IndexedDB every other app uses (
history:retouch), never to a server. They show up in AnubisDB under Retouch, they are included in a local backup, and uninstalling the app offers to erase them.
The one thing to know before you start: an image you have not saved is not kept. The Save button is explicit, not automatic — so press Save (or export) before you close the window. Retouch does warn you before discarding unsaved changes when you open another image or start a new one.
Getting started
Retouch is a Pro app. Install it from the App Store, then open it from the dock. There is no download and no first-run setup — it is ready immediately.
Open an image
The empty state is a dropzone. Three ways in:
- Click it to browse for a file.
- Drag and drop an image anywhere onto the window.
- Paste with
⌘/Ctrl+V— handy straight after a screenshot.
PNG, JPG, WEBP and GIF are accepted. The image is decoded onto a canvas at its natural size; the checkerboard behind it shows transparent regions.
The toolbar
| Control | What it does |
|---|---|
| Rotate left / Rotate right | Turns the image 90° counter-clockwise or clockwise. |
| Flip horizontal / Flip vertical | Mirrors the image. |
| Crop | Opens the crop editor with the whole image selected. Drag any of the eight handles to resize, drag inside the box to move it, or drag on an empty part of the image to draw a fresh selection. Pick an aspect preset (1:1, 4:5, 16:9, 9:16, 3:2) to lock the ratio, or type exact W/H/X/Y in pixels. Arrow keys nudge the box (Shift for larger steps); Enter applies, Esc cancels. Apply crop confirms, Cancel backs out. |
| Resize | Asks for a new width and height in pixels. |
| Adjustments | Opens the colour panel (below). |
| Undo / Redo | Steps back and forth through your edits. |
| Reset to original | Throws away every edit and returns to the image as opened. |
| Zoom out / percentage / Zoom in / Fit | Changes how large the image is drawn. The percentage is a button — click it for 100%. Ctrl/⌘ + scroll over the image does the same. Fit scales the image to the pane; any other zoom lets the canvas area scroll. |
| Save | Keeps the image (and its pending adjustments) in the sidebar. Saving again updates the same entry rather than making a copy. |
| Open another image | Starts over with a new file. |
| Download PNG / Copy to clipboard | Exports the result. |
Adjustments
The Adjustments panel has seven sliders: brightness, contrast, saturation, blur, grayscale, sepia and invert.
They preview live on the canvas without touching the underlying pixels, so you can push a slider around and change your mind for free. Two ways out:
- Apply — bakes the current settings into the pixels, and becomes a single undo step.
- Reset — drops the adjustments and returns the sliders to their defaults.
Adjustments are also flattened automatically if you rotate, flip, crop or resize while they are pending, so a transform never silently discards them.
Exporting
- Download PNG — lossless, keeps transparency.
- JPEG — smaller, written at quality
0.92. JPEG has no alpha channel, so transparent areas will come out solid. - Copy to clipboard — copies the image as a PNG, ready to paste into another app (or into the Clipboard app's history).
The download filename is derived from the file you opened, with the extension swapped.
Your saved images
The sidebar on the left is your image library. Save puts the image you are working on into it, with the adjustment sliders exactly as you left them; open it again later and both come back.
- Click a row to open it. + starts a new image.
- Right-click a row for Open, Rename, Download PNG and Delete. A delete is confirmed once and can be undone from the toast.
- Select (or press and drag across the rows with the mouse) turns on checkboxes, so several images can be deleted in one go — one confirm, one undo that restores them all.
- The library keeps your 24 most recent images; older ones fall off the end.
Everything lives in the local database on your device. It appears in AnubisDB under Retouch, travels in a local backup, and uninstalling Retouch offers to erase it.
Two things worth knowing
Undo is bounded to the last 12 steps. The undo stack keeps twelve full-image snapshots; older ones fall off the end. It is a live editing stack, not part of what is saved — reopening a saved image starts a fresh one. For a longer path back, Reset to original always works.
Saving is explicit. There is no autosave: an image you never pressed Save on is gone when the window closes. Retouch asks before discarding unsaved changes when you open another image or start a new one, but closing the window does not prompt — save or export before you close it.
Architecture
Retouch is UI plus a canvas, with a thin library on top of the shared data store. The code lives in extension/src/apps/retouch/.
Modules
| File | Role |
|---|---|
index.ts | The whole app — the descriptor, the dropzone, the toolbar, the crop editor, the adjustment panel, the undo stack, the saved-image library, and export. |
crop.ts | Pure crop-selection geometry — projecting the pixel selection to and from the on-screen box, resolving handle/move drags, aspect presets, and clamping. Split out so it is unit-tested without a DOM (crop.test.ts). |
zoom.ts | Pure zoom-step maths — the stops the -/+ buttons walk through, stepping from a measured Fit scale, and clamping. Unit-tested in zoom.test.ts. |
retouch.css | Colocated styles — the checkerboard backdrop, the toolbar, the zoom controls, the crop overlay (handles, rule-of-thirds grid, removed-area mask) and the slider panel. |
meta.ts | Identity — id, name, accent (#f43f5e), order, plan: 'pro'. |
There is deliberately no retouch.local.ts. Saved images are a flat list of records plus one blob each, which is exactly what the shared createBlobHistory helper already provides, so there are no app-specific routes to register.
Saved images
Retouch uses the same three shared pieces as Denoise and Screen Recorder, so there is nothing bespoke to maintain:
createBlobHistory('history:retouch')(lib/blobHistory.ts) — newest-first listing, blob-aware delete, and newest-24 pruning over the shareddataStore. Thehistory:<appId>name is the storage convention, which is what makes AnubisDB attribute the data to Retouch with no registry edit.createHistorySidebar(components/historySidebar.ts) withselectable: true— the row list, the right-click menu (Delete is built in; Retouch adds Open, Rename and Download PNG), confirm-plus-undo, and multi-select with drag-to-select, per app convention 2.createSidebarShell(components/sidebarShell.ts) — the sidebar/main row, the drag resizer and the narrow-window drawer.
One record holds { name, at, imageKey, w, h, adjust }; the blob at imageKey holds the raw canvas pixels. The adjust field is the pending (unbaked) slider state — CSS filters never touch the bitmap, so persisting the two separately is what lets a reopened image come back mid-edit rather than flattened. Saving an image that is already in the library reuses its blob key, so a re-save replaces the pixels instead of orphaning a blob.
The app declares dataLabel / hasData / clearData, so uninstalling offers to erase the library.
Retouch is the first pop-out app to use the shared history sidebar, which exposed a latent bug there: the sidebar opened its confirm dialog, undo toast and context menu against the bare document, which in a floating window is the opener's, not the app's. It now scopes all of them (and its drag-select hit-testing) to its own root element, so every app gets the fix.
How an edit works
Why Canvas 2D, and nothing else
The adjustments are not hand-written pixel loops. They are the native ctx.filter string — brightness() contrast() saturate() blur() grayscale() sepia() invert() — which the browser applies on the GPU. That buys two things:
- Live preview is free. While the sliders move, the filter is set on
canvas.style.filter, so the browser composites it for display without the pixel data changing at all. - Applying is one draw.
flatten()sets the same string asctx.filteron an off-screen canvas, draws the image through it once, and swaps the result in.
Transforms are the same idea: rotate, flip, crop and resize are each a single drawImage onto an off-screen canvas with the appropriate transform, which then replaces the working canvas. No dependencies, no WASM, nothing to download — which is why Retouch is the one Pro media app that opens instantly.
Heavier or custom filters would want Photon (Rust to WASM) or a WebGPU compute shader. The editor is structured so a filter can be swapped to such a path without touching the UI, but v1 deliberately does not need one.
Undo stack
snapshot() pushes a full ImageData of the canvas onto an in-memory array, and restore(i) puts one back. It is a plain snapshot stack, not a command log: simple and exact, but the memory cost is one full uncompressed frame per step.
That is the reason for the bound — the stack is capped at 12 entries and the oldest is dropped beyond that. It is not persisted: saving an image stores its current pixels, not its history, so reopening a saved image starts a fresh stack. Reset to original is handled separately: it truncates the stack back to its first entry, so it survives regardless of how many edits have scrolled off.
Zoom
zoom is either null — Fit, where the canvas keeps its CSS max-width / max-height and the browser scales it into the pane — or an explicit factor, which pins the canvas's display size and lets the wrap scroll. Stepping starts from the scale currently on screen (measured in Fit mode), so the first click out of Fit lands on the neighbouring stop rather than jumping to 100%; that rule is the pure nextZoom in zoom.ts.
Nothing in the crop editor knows about zoom: the overlay is projected from the canvas's live bounding rect on every paint, and a ResizeObserver on the canvas repaints it — so changing the zoom moves the selection with the image for free.
Agent tools
Retouch declares eight tools for a future KimtAI agent. They are dormant — no shipped model can call them — and none of them runs today.
Four are stateless transforms on an attached image (needs: { attachment: 'image' }), returning the processed image as an artifact:
| Tool | Would do |
|---|---|
grayscale_image | Desaturates the attached image. |
invert_image | Inverts its colours. |
rotate_image | Rotates it 90° clockwise. |
resize_image | Resizes it to a given width and height. |
Four cover the saved-image library, so it could be driven end to end:
| Tool | Would do |
|---|---|
list_images | Lists saved images with their id, name, size. |
get_image | Reads one image's name and size by id. |
rename_image | Renames a saved image. |
delete_image | Deletes a saved image and its pixels. |
Interactive editing — cropping, dragging sliders — is intentionally not exposed. Those need a live user gesture on a canvas, which an agent has no way to perform, so the app follows the suite convention of only exposing actions that are meaningful without one.
Changelog
1.3.0 — 2026-07-25
- Smooth, continuous zoom — scroll or pinch over the image to zoom
- Zoom stays anchored to the cursor, so the spot you point at no longer scrolls away
- Hold Space (or middle-drag) and drag to pan a zoomed image
- Crop still selects the exact region at any zoom or pan
1.2.0 — 2026-07-22
- Save your edited images, with their adjustments, in a sidebar library
- Right-click a saved image to open, rename, download or delete it
- Select several saved images and delete them in one go, with undo
- Zoom in and out, or fit to the window — Ctrl/Cmd + scroll works too
- Warn before discarding unsaved changes when opening another image
1.1.0 — 2026-07-21
- Rebuild crop into a real editor — handles, presets, grid, keyboard
- Crop the region you drew, at any window size