All notable changes to Fresco are documented here. The format is based on Keep a Changelog and the project adheres to Semantic Versioning.
0.1.2 — 2026-05-14
Small UX + extension-API patch release. No breaking changes for existing consumers; the click-to-zoom default flip is documented below because it's user-visible.
Added
handle.appendNavButton(...)'s returned remover now carries.setIcon(svgString),.setTitle(text), and.el(the underlying<button>element). Extensions can mutate a button after creation without re-adding it (which would reshuffle its position in the nav column). Used by Etcher 0.2's visibility toggle to flip eye ↔ eye-slash.
Changed
- Mouse single-click no longer zooms.
gestureSettingsMouse.clickToZoomdefaults tofalse;dblClickToZoom, scroll-to-zoom, and pinch-to-zoom on touch are unchanged. Single clicks now reliably pass through to overlays that want them (e.g. annotation selection) instead of fighting OSD's built-in click-to-zoom.
0.1.1 — 2026-05-12
Small additive release for layered libraries. No breaking changes.
Added
handle.appendNavButton(svg, title, onClick)— extensions append a button to the same.fresco-navflexbox column that holds the built-in zoom-in / zoom-out / reset / fullscreen. Returns an unsubscribe function that removes the button on cleanup. Used by Etcher to add a pencil button that toggles annotation mode.animationandupdate-viewportevents bridged on the viewer handle (handle.on("animation", fn)). The existingzoom/panevents only fire on the intent of an input; the new ones fire on every spring-interpolated frame so overlays glide with the image instead of jumping at endpoints.
Changed
<Fresco.viewer>now setsphx-update="ignore"on its host div. Without it, LiveView morphdom patches walk the viewer's children on every render and wipe OSD's runtime-added canvas + extension overlays. The hook still receivesupdatedcallbacks for attribute changes (e.g.data-srcswaps continue to work) —phx-updateprotects children only.- Nav column reordered top-to-bottom: fullscreen → zoom-in → zoom-out
→ reset. Extensions appending via
handle.appendNavButtonland at the bottom of the column.
0.1.0 — 2026-05-12
Initial release. Polished pan-zoom image viewer for Phoenix apps, with a deliberate extension surface for layered libraries.
Built-in viewer
<Fresco.viewer id src class>LiveView function component- Pan: click-drag, touch-drag, keyboard arrows
- Zoom: mouse wheel, pinch, double-click, dedicated buttons,
+/-keys - Fit-to-view initial state regardless of image / container aspect ratio
- Heroicons nav overlay at top-left: zoom-in, zoom-out, reset, fullscreen
- Viewport clamped so the image can't be panned off-screen
(
visibilityRatio: 1.0,constrainDuringPan: true) - Smooth animations tuned for snappy responsiveness
(
animationTime: 0.3,springStiffness: 10) - Browser fullscreen mode
Extension surface
window.Fresco.viewerFor(domId)— synchronous lookup of a live viewer handlewindow.Fresco.onViewerReady(domId, callback)— async-safe lookup that fires the callback as soon as the viewer is ready (handles mount-order races when an extension hook mounts before its host viewer)window.Fresco.registerSourceProvider(predicate, factory)— registers a predicate-matched URL transformer; first registered provider that matches wins, falling back to a default plain-image provider- Viewer handle exposes:
imageToScreen/screenToImage,getViewportBounds,fitBounds,setSource,swapSourcePreservingBounds, andon(event, handler)forzoom/pan/open/resizeevents
JS engine
- OpenSeadragon ~> 4.1 lazy-loaded from jsDelivr on first mount
- One bundled JS file (
priv/static/fresco.js); no npm dep, no build step in consumer apps - Heroicons SVGs inlined; no PNG sprite dance against a CDN
Requirements
phoenix_live_view ~> 1.1,phoenix_html ~> 4.0,jason ~> 1.4