Repository navigation
v0.22.0
OpenShop v0.22.0
This release closes every remaining P1 item on the OpenShop roadmap. The headline is that pixel selections now describe the document rather than the screen, and the whole interface is operable without a mouse.
Selections now mean what they say
Masks were stored in screen space but consumed under whatever viewport transform happened to be current. Zooming or panning between selecting and deleting erased a different part of the image, and below 100% zoom the one-to-one mapping left a sparse grid of surviving pixels instead of a clean hole.
- Masks are stored in document space and every consumer reads them that way.
- Delete walks image pixels and asks the mask, so a layer scaled below 100% no longer keeps two pixels out of every three.
- The Lasso selects the shape it encloses instead of its bounding box, mapped through the current zoom and pan.
- Selections carry real 0–255 coverage. Feather keeps the gradient it computes rather than throwing it away and widening the hard edge by a pixel; deleting fades pixels by how selected they are.
- Coverage survives a save and reload; projects written with the older one-bit format still open, and masks saved before this change are rescaled into the document.
Keyboard and assistive technology
- The menubar is fully operable from the keyboard: arrows, Enter/Space, Home/End, type-ahead, and Escape closing one level at a time.
- Menus, rows, separators, and submenu state carry real ARIA roles. Submenu arrows and nested rows no longer leak into a menu's own name — "Filter" used to announce as "Filter ▸ ▸ ▸ ▸ ▸ ▸ ▸ ▸".
- Tab stays inside an open dialog, focus moves into a dialog when it opens, and returns to whatever opened it on close.
- Arrow keys move the selected object, Shift makes the step 10px, Alt resizes, and Ctrl+Alt+Up/Down reorders the active layer — every drag-only interaction now has a keyboard path.
- Text contrast reaches 4.5:1 across all three themes and every pointer target is at least 24×24 CSS pixels, both enforced by automated gates.
Responsiveness and correctness
- Ten more pixel adjustments (Solarize, Vibrance, Exposure, Shadows/Highlights, Photo Filter, Curves, Channel Mixer, Auto Levels, Auto Contrast, Auto Enhance) moved off the main thread into the filter worker, so they can be cancelled mid-run.
- Filters no longer report success before the edit is committed. A result rejected because the document changed used to produce two contradictory toasts and leave Reapply Last Filter pointing at a filter that never landed.
- One consistent rule decides whether an edit is still valid, replacing three copies at three strictness levels.
- Starting an AI operation while another model is downloading now takes over from it instead of killing both.
- The full-screen progress dialog no longer flashes for filters that finish in a few milliseconds.
Testing and truthfulness
- Core flows now run automatically on Firefox and WebKit as well as Chromium (
npm run test:cross-browser). The browser-support table says what is actually verified on each engine rather than claiming blanket full support. - One assertion keeps the version aligned across
package.json,package-lock.json, the README badge, the changelog, the page title, the in-app labels, and the offline shell revision. It immediately caughtpackage-lock.jsonstill declaring 0.20.0. - Test coverage: 47 unit, 44 Chromium end-to-end, 22 cross-engine.
Security
base-uri 'none'andform-action 'none'added to the content security policy; neither falls back todefault-src, so a<base href>injection could previously have redirected every relative URL including the service worker.- The security gate's inline-handler check now catches any
on*=attribute rather than four specific ones.
Known limitation
script-src still allows https://cdn.jsdelivr.net for three SRI-pinned script tags. The host allowance is broader than those tags and remains on the roadmap.
Install
Download openshop-v0.22.0.html and open it in a browser, or use the hosted build. Everything runs client-side.