Repository navigation
Releases: SysAdminDoc/Openshop
Release list
OpenShop v0.31.0
OpenShop now has a clearer product page, four reproducible screenshots, and a social preview built from the live editor.
Highlights
- Choose the hosted PWA, portable HTML file, or self-hosted static bundle.
- Preview the layered workspace, export compatibility report, verified offline shell, and compact layout before opening the app.
- Export valid color-managed WebP files with corrected ICC chunk order and D50 profile matrices.
- Keep long filters cancellable before the progress panel appears.
- Use the stable offscreen worker automatically in Firefox.
Verification
The complete local release gate passed. It covered security policy and runtime integrity, dependency auditing, 4K to 8K performance budgets, unit coverage, 311 Chromium and hosted tests, 158 Firefox and WebKit tests, plus 12 mobile-browser tests.
Downloads
openshop-v0.31.0.htmlis the portable network-first editor.OpenShop-v0.31.0.zipcontains the self-hosting files, screenshots, icons, and documentation.SHA256SUMS.txtverifies both downloads.
Openshop v0.29.0
Openshop v0.29.0
Covers everything since the last published release (v0.24.0 → v0.29.0). Five releases in one: this span implements every request from issue #3 plus a large feature, security, and correctness program.
Issue #3 — all six requests shipped
- Physical document sizes (v0.26.0): New Image takes millimetres or inches at a chosen PPI, converts live between units, ships A4/Letter/6x4in presets at 300 PPI, and the document carries its resolution into PSD and PDF export.
- One layer per text/shape object (v0.25.0): creating text or a shape mints its own named layer, Photoshop-style; the old stacking behaviour remains as a preference.
- Brush/eraser paint into the layer (v0.26.0): a finished stroke is composited into the layer's pixels and the editable path discarded — an "erasure" can no longer be dragged around afterwards. Lasso and pen gained start/end close "suction" with a lit close handle.
- Snapping (v0.26.0): objects snap edges, centres and midpoints to the artboard and to every other object with smart guides; Alt suppresses per drag; tolerance scales with zoom.
- Photoshop shortcuts: single-key tool map (V move, T text, and the rest) with the full list in the Shortcuts panel.
- Resizable right-panel sections (v0.26.0): drag bar between Layers/History/Properties, keyboard-operable (WCAG 2.5.7/2.5.8), Home/double-click restores, sizes persisted.
Highlights by release
- v0.29.0: canonical asset manifest driving loader/service-worker/security-checker; keyboard-operable Layers/History listboxes; document migration registry with rollback-safe future-schema rejection; peer-identifiable revision-safe WebRTC sessions; deterministic 4K/8K/12MP performance-budget runner in the release gate; cross-engine mobile capability matrix; plugin manifests with SHA-256 provenance and deny-by-default capabilities; cancellable batch runs; ABR tips rendered as raster stamps.
- v0.28.0: PDF import (each page an editable layer); animated WebP/APNG import with timeline durations; camera RAW import via pinned LibRaw/WASM; non-destructive Levels/Curves/HSL adjustment layers; independent raster layer masks; re-editable embedded Smart Objects; vector-shape-to-path conversion with Bezier handles; text-on-path; WebGPU filter compute with WebGL2/CPU fallback; 64×64 dirty-tile undo deltas (history ring 60 → 120); sandboxed iframe plugin API; ICC profile round-trip in PSD; folder batch processor; no-server WebRTC collaboration; ASE/GPL/JSON palette + ABR brush + GRD gradient import; persistent Mobile workspace.
- v0.27.0: script-policy release gate hardened; offline worker constrained to shipped assets; versioned
postMessageembed contract; named history states with branch archiving; SVG import as editable objects through the sanitiser; raster-to-vector tracing; true vector PDF export; Swin2SR super-resolution enlarger; on-canvas gradient stop editing; text decorations with independent colour/thickness; outbound network ledger with strict offline mode; Transformers.js 4.2 with pinned models; AVIF import/export; EXIF JPEGs no longer rotated twice. - v0.26.0: boolean selection modes (add/subtract/intersect); Windows High Contrast / forced-colors support; EXIF orientation on import; diagnostics export (ring buffer of last 200 errors, no document data); translatable toasts and command labels with honest parity metric; large-image slider responsiveness.
- v0.25.0: keyboard usability restored (Tab traversal, modal focus trap, welcome overlay released); selection sampling fixed at every zoom and on HiDPI; Grow/Similar write full coverage; delete-selection deletes pixels, not the tint; single
OS.versionconstant with a release check; destructive crop/flatten/rotate confirm what they discard; PDF export stream compression (3× smaller); ag-psd 31 with allocator-enforced memory ceiling.
Verification and one honest caveat
Before closing issue #3 I wrote one browser test per request — six in total — that drive the running editor rather than reading the changelog. All six pass, and they ship in the repo so a regression shows up in the suite instead of in a second bug report.
Doing that turned up something worth saying plainly: the Chromium end-to-end suite was already red on the v0.29.0 tree, ten failures, none of them related to issue #3. Four are fixed in this release:
- the selected bottom tab failed WCAG 2.2 text contrast (4.01:1 against its own tinted background)
- the workspace selector and the tool options Reset button were under the 24x24 pointer-target floor at 22px and 20px tall
- the tool family button never showed its active state on first paint
- the offline launch-queue test was written before the editor gained its blank workspace
Six remain open and are written up as a P0 at the top of ROADMAP.md, each with what it actually reports: mobile and tablet layout blocks that fight each other, a command-replay mismatch, the Photon WASM parity check, the sandbox plugin handshake, the queued-launch consumer, and Chinese coverage for the ~40 strings the audited tool inventory added. That last one needs a native speaker rather than a bulk machine translation, so it stays open on purpose.
Assets
openshop-v0.29.0.html— the single-file editormanifest.webmanifest,sw.js— PWA shell (shell revision0.29.0-r2)
v0.24.0
OpenShop v0.24.0
This release closes the last of the audit findings. Most of it comes from finally running things that had only ever been read — the AI pipelines, the WASM filter backend, and the exported PDF and PSD files — and several of them turned out not to work at all.
Every AI feature was broken
Background Removal, Segment Select, Depth Map and Object Detection each handed the model a data: URL. Transformers.js reads a URL with fetch(), and connect-src does not list data: — so the request was blocked the instant the model finished downloading. The model loaded, then nothing happened.
They now receive canvas pixels directly, which also skips a full-image PNG encode and decode. Verified end to end against the pinned MODNet weights: 3.3 s cold including the 25.9 MB download, 0.8 s warm.
Relatedly, the Offline & Install dialog and the backend report both claimed no model was loaded while background removal was holding one — its handles live outside the pipeline map.
Photon's filters are not this app's filters
The optional WASM backend was measured against the JavaScript worker on a fixed 16x16 input. Its grayscale differs by up to 58 levels — it does not use the Rec.601 weights the rest of the app and the histogram use — its sepia by 192, its threshold flips pixels outright, and its sharpen and emboss convolutions zero the alpha of the outermost pixel ring, leaving a transparent one-pixel frame.
Which result you got depended on whether an optional download happened to succeed. Only invert agrees, so only invert is accelerated now. The measurements are a test, so a Photon upgrade that fixes them shows up as a failure rather than going unnoticed.
Exports were the wrong physical size
- PDF: jsPDF's
pxunit produced an 800x533pt page for a 600x400 document — an 11.1 inch wide page at roughly 54 DPI. Pages are now sized in points from CSS pixels (450x300pt, 6.25x4.17in at 96 DPI) with the raster still at full resolution, and the file carries a title, creator and language. - PSD: no resolution resource was written at all, so the document had no DPI and its physical size was whatever the reader defaulted to. It now declares 96 PPI.
Both were verified by reading the written bytes with tools that share no code with the exporters — an independent PSD parser and veraPDF. Photoshop and Acrobat were not available, so how Adobe renders these files is still unverified; the details are in RESEARCH.md.
Security
script-srcno longer names a CDN. Fabric, ag-psd and jsPDF were<script src>tags on jsDelivr, and CSP does not require SRI on scripts it permits by host — so an allowance covering three pinned tags also let any HTML-injection sink load an arbitrary npm package. All three are now fetched, SHA-384 verified in page, and executed fromblob:URLs, the same path the eight lazy assets already took. Substituted bytes stop the editor with a visible message instead of quietly becoming the engine.- Exported SVGs are judged on every
hrefregardless of namespace, against an allowlist. The old[xlink\:href]selector matched nothing — attribute selectors match the local name in the null namespace, andxlink:hrefis exactly what fabric emits for images — so that branch was dead, and the plain-hrefchecks were case-sensitive.
Correctness
- Autosave no longer captures a document mid-load. Dimensions were assigned before the canvas finished loading, so a capture landing in that window persisted the old document's content at the new document's size.
- Recovery ownership stops flapping when another tab owns the stream. Each undo re-installed the contested document id and the next autosave renamed again, orphaning generations that were later offered as unsaved work.
- Cyclic PSD group metadata no longer silently drops layers from an export.
- The service worker's runtime cache is versioned with the shell, capped, and refuses opaque responses — an opaque response hides its status, so a captive-portal or CDN error page was kept and served forever.
Cross-engine truth
A capability probe now runs on all three engines and asserts the fallback for each optional platform feature. One finding is worth stating plainly: WebKit gives a file:// origin no origin-private file system, so opening the single HTML file directly in Safari has no auto-save and no crash recovery. Host it and both come back. The browser-support table says so now.
Consistency and performance
- One treatment per component. Sliders had three thumb designs and Firefox showed the pre-redesign thumb everywhere; there is now one design on both vendor pseudo-elements, verified in Chromium and Firefox. Radii collapse to a 6/8/12 scale, menu-like rows share one hover treatment, and
transition:allis replaced by named properties on three duration tokens. - Animation playback moves the highlight instead of rebuilding the thumbnail strip on every tick — a 20-frame timeline at 12 fps was doing roughly 240 image decodes a second to move a border.
- The duplicated model-load path is one helper, and the PSD import stops keeping a second registry of a job the compute controller already tracks.
Tests
64 unit, 69 Chromium end-to-end (including the offline-shell contract), 28 cross-engine on Firefox and WebKit.
Install
Download openshop-v0.24.0.html and open it in a browser, or use the hosted build. Everything runs client-side.
v0.23.0
OpenShop v0.23.0
This release closes every remaining P2 item on the OpenShop roadmap. The theme is controls that told the truth about themselves — several visible options did nothing at all — plus two performance ceilings and a real right-to-left contract.
Controls that did nothing now do something
- New Image background — the colour picker was read by nothing, so every new document came out transparent whatever you chose. The dialog now offers Transparent, White, or a custom colour, and the swatch is enabled only when it applies.
- Recent files — the welcome screen's Recent list was permanently empty because nothing ever recorded an opened document. It now populates, and the rows are presented as the history record they are rather than as clickable shortcuts that did nothing.
- Palette import — the file picker advertised
.gpland.ase, but the reader only ever ranJSON.parse, so picking either reported "Invalid palette file". Both formats now parse for real, including ASE's RGB, CMYK, Gray, and LAB colour models. - Preferences — "Preferences saved" meant the language only. Default canvas size, grid size, snap tolerance, history cap, and accent colour are all persisted now, and a corrupted store is clamped on the way in rather than being able to disable undo.
- Smart Upscale — renamed to Enlarge (resample) and moved out of the AI menu. It is stepped canvas resampling with a sharpening pass; no model is involved and it should never have claimed otherwise.
- AI backend — the README promised WebGPU with a WASM fallback while both pipelines pinned
device: 'wasm'. OpenShop now probes for a usable adapter once and reports which backend it chose.
Performance
- Levels and Color Balance stayed responsive only on small images. Each slider tick ran a full-resolution pixel pass, encoded the result to a PNG data URL, and decoded it again — hundreds of milliseconds per tick on a 12 MP photo. Previews now run on a downscaled proxy, swap the working canvas straight into the layer, and use a 256-entry lookup table instead of three
Math.powcalls per pixel. Apply still commits at full resolution. - Undo history was capped by entry count only. Because each entry embeds full base64 image sources, 60 steps on a large photo could retain gigabytes. History now evicts against a 192 MB budget as well, always keeping at least one entry, and Image Information reports the retained size.
Localisation and right-to-left
- Changing locale now sets the document's
langanddir, which assistive technology, hyphenation, and bidirectional text all depend on and which the locale switch never touched. - Canvas text carries an explicit direction, and the menu chrome uses logical properties, so a right-to-left locale no longer strands shortcuts and submenu arrows on the wrong edge.
- A new pseudo-locale accents and brackets every translated string, making any interface text that skipped the localisation machinery obvious at a glance. The Chinese map is now gated at parity with English apart from format names and single-letter typographic controls.
Model cache
Each pinned model's cached size and load state are reported, and a single model's files can be cleared without wiping all site data.
Maintainability and coverage
- The two competing mobile stylesheets are now one. The first block was almost entirely overridden — a 36px topbar against 44px, a flush-bottom toolbar against the floating one, a 200px tablet panel against 248px — so edits to it did nothing and any reordering would have flipped the mobile layout wholesale. The animation timeline also now clears the floating toolbar instead of sitting under it.
- New tests cover history eviction and the baseline fallback, entry coalescing, the edit-commit guard, the byte budget, and the filter worker's crash path. Each was checked by reverting the branch it guards and confirming the test fails.
- Test coverage: 56 unit, 59 Chromium end-to-end, 24 cross-engine on Firefox and WebKit, 3 offline-shell contract.
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.23.0.html and open it in a browser, or use the hosted build. Everything runs client-side.
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.
v0.21.0
Fixed
-
Stop the import sanitizer from rewriting the editor's own snapshots: undo, redo, transaction rollback, project open, and recovery restore now preserve multi-line text, text longer than 500 characters, and base64 image sources exactly
-
Keep selection overlays out of PNG, JPEG, WebP, PDF, PSD, flatten, crop, and before/after captures; the tint no longer bakes into exported or flattened pixels at any zoom level
-
Stop a second command started during an in-flight asynchronous command from rolling back the first command's work
-
Keep the document marked unsaved when an edit lands while a project save is clearing recovery generations
-
Confirm before replacing a document that has unsaved changes, from New Image, templates, Open Image, Open Project, Open PSD, drag and drop, and installed-app launches, with a Save first option
-
Show the crash-recovery offer above the welcome launcher instead of behind it, so it is visible on the first run after a crash
-
Stop the hosted offline shell from rolling back an update after a single unconfirmed navigation; opening a second tab, refreshing during load, or closing the tab early no longer discards a healthy update, the rolled-back shell cache is retained, and a Rebuild Offline Shell action can re-stage without waiting for a new revision
-
Report a cached shell against the asset manifest that populated it, so changing the pinned asset list no longer reports a complete shell as incomplete forever
-
Make the Midnight and OLED themes apply to the whole studio: the precision-studio chrome now draws from the design tokens instead of ~170 hardcoded literals, so the topbar, toolbar, panels, dialogs, status bar, and canvas well all follow the selected theme, and the canvas-drawn rulers, curves grid, histogram, navigator, and before/after chrome repaint on a theme change
-
Persist the selected theme across reloads and apply it during startup rather than after the welcome screen is dismissed
-
Validate numeric dialog input instead of silently substituting defaults: New Image, Resize Canvas, and Preferences now clamp to their declared ranges, so a negative or empty value can no longer create an invalid canvas or disable undo by setting a non-positive history limit
-
Reject invalid amounts in Expand, Contract, and Border Selection, and keep the existing selection when the operation would clear it, instead of wiping it and reporting "expanded by NaNpx"
-
Show the accent colour currently in effect when Preferences opens, so applying an unrelated preference no longer resets a customised accent
-
Keep toasts readable: errors stay on screen long enough to read, long messages wrap instead of overflowing, hovering pauses dismissal, clicking dismisses, and toasts are no longer hidden behind the timeline, macro, Liquify, or before/after surfaces
-
Close filter panels, Liquify, and before/after with Escape instead of falling through to the canvas and clearing the selection while the panel stays open
-
Keep modeless workspace panels below modal dialogs so a dialog is never overlapped by an un-dimmed panel
-
Stop the status bar from re-announcing on every pointer move, and announce each toast once instead of twice
-
Replace version-control jargon in the save-state and offline chips with plain language
-
Report images that fail to decode instead of doing nothing at all, and stop renaming the open document when an open fails
-
Bound animated GIF import by frame count and decoded size, close the decoder on every path, and discard a slow import if the document changed meanwhile
-
Accept PSD and
.openshopfiles dropped anywhere in the window, not only over the canvas, and say when extra dropped files are ignored -
Allow SVG in the Open Image picker, which previously advertised SVG but greyed it out
-
Walk one step per undo when undo or redo is triggered faster than a restore completes; overlapping restores no longer interleave or mis-map layer membership
-
Preserve layer masks, per-object opacity, blend mode, skew, shadow, and the object's own name when a filter or AI operation commits pixels
-
Report filter failures instead of leaving the dialog open with no feedback when a worker errors
-
Make Ctrl+K work on the welcome screen where it is advertised, and stop advertising Ctrl+Shift+P and Ctrl+N, which the browser reserves; the fullscreen shortcut is now listed consistently as F
-
Confirm dialogs with Enter, matching the existing Escape-to-cancel behaviour
-
Explain when the command palette has no matches and when its list is truncated
-
Report the real outcome of Batch Export instead of always claiming success, and say when no format is selected
-
Offer an inline undo when clearing the palette or recorded actions, which canvas history cannot recover
-
Warn once that animation frames are flattened snapshots before the timeline replaces a multi-layer stack
-
Translate the renamed Save Project menu item in Simplified Chinese
-
Restore the previous document when opening a project or recovery generation fails partway through, instead of leaving a half-replaced canvas whose layers panel, history, and save state disagree
-
Enforce the PSD decode budget before any pixels are allocated by reading the layer structure first; the previous
totalMemoryLimitoption does not exist in ag-psd and was silently ignored, so a small crafted file could exhaust memory during decode -
Export eraser strokes as erased pixels rather than solid black in PSD layers
-
Release sticky-note drag listeners when a note is deleted instead of leaving document-level handlers behind for the session
-
Retry a lazily loaded runtime library once bypassing the HTTP cache when its integrity check fails, so a poisoned cache entry no longer disables that feature until the cache expires
-
Make template cards, New Image size presets, and the zoom indicator real buttons so they can be reached and activated from the keyboard, and give the layer visibility and lock controls accessible names
-
Keep the export dialog's alpha preference when the JPEG format button is clicked more than once
-
Report GIF export failures, clamp the frame rate to a usable range, and release the exported blob
-
Explain why recovery actions are unavailable for a corrupt generation instead of showing an unexplained disabled button
Performance
- Stop encoding a full-resolution PNG of the whole document on every edit and every zoom step: the navigator now renders at thumbnail scale, zoom and pan update only the viewport rectangle, and minimap and histogram refreshes coalesce into one frame and skip entirely while their panels are hidden
Removed
- Delete unreachable code: the unused layer-rebuild, legacy recovery-restore, duplicate new-document and background-removal wrappers, and a PSD branch that could never run
Changed
- Reimagine the editor as a high-contrast precision studio with a floating tool dock, structured inspector cards, technical canvas workspace, local-only trust indicator, and compact ready state
- Replace the welcome screen with a responsive local-first workspace launcher whose templates and primary actions remain reachable from phone through desktop widths
- Make mobile inspector groups independently usable through a bounded, scrollable drawer with no horizontal page overflow
- Unify project save/open, recovery, and history on document schema v1 with stable layer/object identity, masks, guides, selections, animation, active-state preservation, and legacy OpenShop/Fabric migration
- Make project and recovery writes transactional with visible clean/dirty/saving/saved/error states, acknowledged worker autosaves, revision-safe concurrent edits, and stale file-handle resets on new/open/recovery flows
- Move the complete PSD decode into a cancellable worker and atomically prepare every decoded layer before replacing the open document
- Keep all onboarding actions and dialog footers reachable at supported phone, tablet, portrait, and landscape sizes with safe-area spacing, touch-sized controls, and keyboard dismissal
- Keep layer ownership, panel order, Fabric stacking, export order, and edit eligibility synchronized; lock, visibility, opacity, blend, rename, and reorder changes now round-trip through history and project files
- Replace label-based macros with validated schema-v1 commands and atomic action replay; initialize history without a fake edit, coalesce live previews, and make crop, flatten, canvas rotation/flip, and frame changes fail-safe and exactly undoable
- Make raster export alpha/matte behavior explicit with real previews and format-loss guidance; keep checker pixels out of PNG, WebP, JPEG, SVG, and PDF output, restore temporary canvas state on failure, and leave project dirty state untouched
- Preserve nested PSD groups, supported blends, 0–1 opacity, visibility, locks, and basic editable text across import/export/reimport; avoid composite-layer duplication and report precise whole-document or per-layer raster fallbacks for unsupported semantics
- Replace the singleton autosave with checksum-verified immutable OPFS generations, staged promotion, bounded retention, corrupt-newest fallback, legacy migration, quota/durability UI, per-generation recovery actions, and cross-tab ownership forks
- Split distribution into a truthful network-first standalone file and a hosted PWA with a verified offline shell, health-confirmed updates, automatic rollback, install/cache diagnostics, and installed-app image/PSD/
.openshoplaunch handling; project saves now use the dedicated extension while legacy.jsonremains readable - Route PSD import, worker filters, AI inference, and chunked pixel post-processing through cancellable document jobs that reject pending work, terminate disposable workers, discard stale replies, and commit pixels/history only while the original document revision and target remain current
Security
- Upgrade Fabric.js from 5.3.1 to 7.4.0 wi...