Skip to content

Releases: johnny4young/vitrine

v1.2.3

Choose a tag to compare

@github-actions github-actions released this 17 Sep 04:00
Immutable release. Only release title and notes can be modified.
8fe8e9e

Vitrine 1.2.3 makes the editor responsive while you type and style. It stops the work each
keystroke and inspector step repeated for nothing: re-measuring the whole window,
re-evaluating the editor and its inspector, reapplying the font to the whole document, and
re-highlighting results it had just thrown away. It also takes development hooks out of
the signed build and stops compiling the command line into the app.

Performance

The timings below were measured on macOS 26 Tahoe.

  • Stop re-measuring the whole editor window on every keystroke. Its hosting controller
    kept the default sizing options, so every update measured the entire SwiftUI hierarchy
    to refresh the window's size limits: 71% of the main thread while typing. The editor now
    measures its minimum size when the window opens and when a live resize starts, and pins
    it with required constraints, so the minimum is unchanged. Per keystroke in a 60-line
    document, the Debug perf scenario went from 52 to 17 ms, and an optimized build from 79
    to 13.3 ms.
  • Keep keystrokes from re-evaluating the editor, its inspector, and the annotation overlay.
    Those views read style fields through a configuration that also carried the document
    text, so each of them re-evaluated on every keystroke. They now read a style
    configuration without the text, and the few views that show the text observe it
    on their own. Per keystroke, the perf scenario went from 17 to 5 ms, and the inspector
    hosted on its own from 3.0 to 0.23 ms.
  • Apply the code editor's font only when its name, size, or ligature setting changes.
    Setting the same font on every update laid the whole document out again: a keystroke in a
    300-line document went from 14.2 to 10.3 ms.
  • Evaluate the editor once per padding or font-size step instead of twice. The preview
    card's measured size lived in the editor's own state, so every size change became a
    second update of the whole editor. A padding step's median went from 36.9 to 20.1 ms,
    the same as a corner-radius step.
  • Keep up to 16 highlighting results per representation instead of 8, enough for one
    document at every font-size step and in every built-in theme. Moving back across the
    slider or through the themes re-highlighted what the first pass had produced. Cache keys
    now compare the document text last. With a 60-line document, the slowest font-size steps
    (p95) went from 56 to 46 ms.
  • Remove stale per-window settings from earlier versions in the background instead of on
    the launch path. Fifty stale suites cost 14.6 ms before the menu bar icon appeared.

Security

  • Compile the development and release-QA launch hooks, and the memory journeys, only into
    Debug builds. The signed, notarized app carried them, including a switch that replaced the
    Web Snapshot renderer with a fake one. They were reachable only through launch arguments,
    and every consumer is a Debug build.
  • Raise the website's sharp override to 0.35.4 for GHSA-rgj7-g3m4-5g8c, a libheif issue
    in the site's build tooling. The app does not include sharp.

Changed

  • Compile the command line into a VitrineCLICore static library, linked by the
    vitrine-cli tool and a hostless test bundle. The app no longer compiles the argument
    parser, batch renderer, or git diff loader it never runs. Recorded production coverage drops from about 51.7% to 48.9%, because
    the old figure counted those lines twice.
  • Move the code formatter, language detector, asciinema reader, file input loader,
    filename suggestion, and share links out of the app into VitrineDomain or
    VitrineRendering, shrinking the CLI's hand-maintained source list. Split
    BackgroundImageStore's remote fetch into RemoteImageFetcher and its decoded-image
    cache into DecodedImageCache.
  • Import VitrineDomain and VitrineRendering explicitly, delete the typealias files that
    hid those dependencies, and enable MemberImportVisibility for every target.
  • Call the Web Snapshot window and the session store directly, stop compiling the
    background editor into the CLI, and drop @MainActor annotations the module default
    already provides.
  • Gate a release tag on the tagged commit's CI instead of re-running it. The candidate's
    verify job keeps the tag, version, and changelog guards, then requires the commit's
    static checks, builds, and UI tests on both macOS rows to have passed, waiting up to 45
    minutes.
  • Share the macOS toolchain setup across workflows through one composite action; read
    MARKETING_VERSION through one script; add make bump for the version lockstep; lint
    the Python gate scripts with ruff and report npm audit findings; and compare CI
    performance medians with recorded baselines.
  • Run the repository-contract and command-line suites in hostless bundles, and the
    formatter suites in the domain bundle.
    Derive the settings persistence guards from SnapshotConfig itself. Have the visual tour
    wait for each surface to stop changing instead of sleeping, and confirm each menu choice.

Fixed

  • Compile the app and its unit tests with Xcode 27. Swift 6.4 rejected the annotation
    shapes' Shape conformance and actors conforming to protocols that inherited the module's
    main-actor default.

v1.2.2

Choose a tag to compare

@github-actions github-actions released this 10 Sep 19:50
Immutable release. Only release title and notes can be modified.
d4e3377

Vitrine 1.2.2 repairs the update channel itself, closes two ways a private destination
could be reached during a web capture, and makes the editor responsive on the inputs that
were slowest: large source files and large terminal captures.

Changed

  • Extract portable models, recipes, search, terminal policies, settings defaults, and
    bounded file/transport safety into a hostless VitrineDomain module shared by the app
    and CLI. The CLI now compiles only its render-facing source set instead of dragging app
    lifecycle, windows, Settings, menu-bar, onboarding, Recents, StoreKit, or WebKit UI.
  • Link the app and CLI against one static VitrineRendering engine for canvas layout,
    highlighting, image policy, render budgets, and encoding. Direct module tests plus an
    App/CLI normalized-pixel contract protect the shared output from boundary drift.
  • Measure build boundaries against the real VitrineDomainTests target rather than a
    temporary copied-source package, while preserving the matched app-hosted probe.
  • Split terminal-screen scanning, ANSI dispatch, cell operations, and serialization into
    focused portable components, and separate Web Snapshot document lifecycle, capture
    orchestration, window presentation, and authenticated-session ownership without changing
    output or user-facing behavior.
  • Generate CLI parsing, aliases, required-value arity, constrained-command allowlists,
    mode-only validation, and 80-column help from one dependency-free argument schema while
    preserving every command, alias, error contract, and render option.
  • Retain exact Highlightr 2.3.0 behind the shared rendering adapter after a measured
    replacement review found incomplete theme compatibility and a 61.8% uncached-medium p95
    regression in its recommended successor. Record explicit migration gates in ADR 0001.

Fixed

  • Refuse a URL capture navigation that is not a web scheme, or that carries no host, in
    the frame the capture is rendering. The entry URL was validated once before the load,
    but a later navigation with no host — file:, data:, about: — skipped the host
    filter entirely. A navigation aimed at a new window is dropped rather than failing the
    capture, so a page that opens a popup still renders.
  • Refuse IPv6 literals that embed a private IPv4 address through the 6to4 and NAT64
    transition formats, and the whole local-use translation prefix, which is registered as
    special-purpose and not globally reachable. A private destination could previously be
    spelled entirely in IPv6 and never reach the IPv4 table.
  • Start the direct-download build's background update scheduler at launch. Sparkle's
    controller is configured to schedule checks as soon as it exists, but it was created
    only when someone opened "Check for Updates", so an install that never used that menu
    command was never offered an update. Sparkle's one-time prompt asking whether to check
    automatically now appears on the next launch.
  • Validate every built-in syntax stylesheet against the engine catalog and fall back
    deterministically to One Dark if a stylesheet cannot load, instead of silently reusing
    the previously rendered theme.
  • Keep the clean-Mac QA bundle free of AppleDouble sidecars, and fail the build if any
    appear, so the archive a reviewer opens matches the one that was verified.

Performance

  • Reuse the most recent highlighting result for a document too large for the derived
    caches. Editing a 90 KB file re-highlighted the same text three times per settle — once
    for the editor, again for the preview, again for the gutter — which took 473 ms against
    a 250 ms quiet window, so typing never caught up. It now takes 190 ms.
  • Reuse the most recent terminal frame for a capture too large for those caches, and
    render captures above 512 KB as plain text. A two-megabyte capture cost 2659 ms per
    settle on the main thread; it now costs 1096 ms. Above the ceiling the escapes are still
    resolved away, so line redraws collapse exactly as they do in a colored render, and the
    editor shows the same notice a large source document gets.
  • Decode a persisted image background before the first canvas draws it, instead of inside
    that first pass. A 24 MB photo background cost 207 ms of the launch's first frame.

Removed

  • Remove the CodeQL analysis lanes. They ran for one release cycle and produced one alert,
    already fixed, while never gating a merge. The Swift lane traced a full Xcode build on a
    hosted runner and was killed by a timeout in 14 of its last 26 runs. Sanitizer lanes, the
    SSRF host policy and its WebKit rule set, the secret scanner, and the coverage floor over
    critical logic are unchanged.

v1.2.1

Choose a tag to compare

@github-actions github-actions released this 02 Sep 20:39
Immutable release. Only release title and notes can be modified.
8b5a902

Vitrine 1.2.1 is a focused safety candidate. It bounds every raster render allocation before
its bitmap is created, makes failures actionable across app and automation surfaces, and
strengthens Web Snapshot isolation without changing the supported workflow or public
distribution contract.

Added

  • Add shared preview and export render budgets with overflow-safe checks for logical
    dimensions, scale, total pixels, and estimated concurrent buffers.
  • Add typed tooLarge, allocationFailed, encodingFailed, and cancelled render
    failures with consistent user-facing messages and CLI exit behavior.
  • Add CodeQL security-extended analysis for Swift and JavaScript/TypeScript, plus
    focused weekly/manual Address Sanitizer and Thread Sanitizer evidence lanes.

Changed

  • Clamp full-page Web Snapshot height against page, axis, pixel-area, and estimated-memory
    ceilings before asking WebKit to allocate the snapshot.
  • Bound syntax-highlighting caches by cost, debounce interactive work, and switch very large
    documents to an explicit plain-text mode instead of retaining duplicate attributed copies.
  • Validate image metadata before decode, normalize supported imports to one static frame, and
    downsample with ImageIO inside the shared render budget.
  • Move living-file metadata and bounded reads off the main actor, with cancellation and
    generation guards when a document changes or its window closes.
  • Preserve the existing macOS 15 Sequoia floor, macOS 26 Tahoe qualification matrix,
    and universal Apple silicon + Intel direct-download contract.

Fixed

  • Reject extreme editor, CLI, App Intent, batch, social-card, comparison-board, Web
    responsive-board, and Web Snapshot renders before bitmap allocation instead of risking
    process termination or a blank result.
  • Propagate render and encoding failures through copy, save, share, batch, and automation
    surfaces instead of collapsing them into generic or silent failures.
  • Recheck actual WebKit image dimensions before composition so an engine result cannot
    bypass the preflight budget.
  • Collect remote image bodies in bounded chunks and cancel the request as soon as its byte
    ceiling is crossed instead of accumulating an unbounded async byte sequence.
  • Release editor-window and code-editor resources on teardown, backed by comparable
    20/50/100-iteration image, window, WebKit, and large-document memory journeys.
  • Bound shell startup-file inspection to 1 MiB on one locked regular-file descriptor, append
    only the helper suffix, canonicalize CLI symlink targets, and atomically replace stale links
    without deleting regular files.

Security

  • Block literal localhost, LAN, link-local, metadata, reserved, IPv6-private, mapped IPv4,
    and ambiguous numeric WebKit subresources across images, CSS, scripts, frames, fetch,
    WebSockets, and other resource types. Explicit loopback opt-in remains narrow and does
    not allow other private destinations.
  • Compile the production content-rule list in a real WebKit test and add a clean-Mac
    zero-request loopback probe. Public-host DNS resolution and rebinding remain documented
    residual risks because WebKit rules match request URLs rather than resolved addresses.
  • Require canonical unpadded base64url for local snapshot links and reject alternate alphabets,
    whitespace, padding, impossible lengths, and ambiguous tail bits before decompression.

v1.0.1

Choose a tag to compare

@github-actions github-actions released this 08 Aug 16:34
Immutable release. Only release title and notes can be modified.
19e4c51

A stability release. Every user-facing change here is a fix found by a systematic audit
of the 1.0 codebase: two crashes, two paths that silently lost work, four terminal
rendering faults, and a set of resources the app never released.

Fixed

  • Restoring an editor window no longer drops part of the document. Five fields
    survived the window's own state but not its restoration, so a reopened window came
    back with the style intact and parts of the content missing. Restoration now carries
    the complete document, and two crash paths on the same route are closed.
  • Work started in a window no longer outlives it. Renders, watchers, and consent
    prompts kept running after their window closed, so a result could arrive with nothing
    left to deliver it to. Each window now cancels what it started when it goes away.
  • Shadow depth now travels with the rest of the style. Saving a preset, exporting a
    recipe, or restoring a session kept every other style value and quietly reset the
    shadow, so a style that looked right in the editor exported flat.
  • Batch exports can no longer overwrite each other's output. Two sources whose names
    resolved to the same file — including names differing only in case or in Unicode
    normalization, which macOS treats as one file — silently produced a single image
    instead of two. Each output name is now claimed against the filesystem's own notion of
    identity before anything is written.
  • clear && command no longer leaves the cleared transcript in the capture. The
    routing that decides between transcript and full-screen rendering counted a partial
    erase as a whole-display one, so the text you cleared stayed in the image.
  • Terminal escape sequences that carry data no longer print as text. Sequences a
    terminal consumes silently (DCS, SOS, PM, APC) appeared as literal characters in the
    capture, and a stray BEL inside one could end it early.
  • Private terminal control sequences are no longer executed as standard ones. A
    sequence a real terminal ignores could move the cursor or erase the screen in the
    capture, so full-screen apps rendered wrong.
  • Per-window preference files no longer accumulate on disk forever. Each editor
    window created a volatile preferences suite that was never removed, leaving thousands
    of orphan files on a long-lived install. They are cleaned up when the window closes,
    and a launch sweep removes any left by earlier versions.
  • Dismissing a pinned snapshot now releases its image. The floating reference panel
    is reused, so closing it — by unpinning or by its title-bar button — kept the
    full-resolution bitmap resident until the next pin or app quit.
  • The Welcome window's step tiles no longer touch the hero band. They sat directly
    on the seam where the gradient ends; there is now a gap between the two.

Changed

  • Vitrine is described by what it does best. The README, repository description, and
    documentation now lead with terminal capture, and
    docs/ARCHITECTURE.md explains the two rendering engines —
    transcript and screen — and how a capture is routed between them.
  • The unused render-routing indirection is gone. RenderCoordinator, CodeRenderer,
    and the classification helper beside them had no caller in the shipping app and
    duplicated logic the live path already performed; their tests now pin the live path.

Security

  • undici is pinned to the patched 7.29.0 for the documentation site's build
    toolchain, and the site's dependency group and the Sparkle updater pin are current.

v1.0.0

Choose a tag to compare

@github-actions github-actions released this 02 Aug 17:35
Immutable release. Only release title and notes can be modified.
e6e2e96

Vitrine 1.0 is the first stable release of the complete local capture workflow: create a
single polished image from the menu bar, keep it synchronized with an explicitly opened
file, reuse a portable visual recipe across a workspace and the CLI, or turn several
finished captures into one comparison board. The release keeps those workflows local,
explicit, and understandable after the image leaves the Mac.

Added

  • Portable workspace recipes. Export the current style, safe header metadata, output
    defaults, and an optional custom theme into a versioned JSON document with no source,
    workspace, output, history, or credential paths. The app can associate that recipe with
    a folder through a machine-local read-only bookmark, but only an explicitly dropped
    source file triggers matching; Vitrine never scans the repository.
  • Deterministic recipe automation. The CLI accepts one explicitly named recipe through
    --recipe and exposes PRO-free recipe validate and recipe show inspection commands.
    Resolution is predictable: built-in defaults, destination sizing, recipe values, a
    named built-in style preset, and finally explicit CLI flags.
  • Session-only living snapshots. Open one source file from the editor and a clean
    document refreshes after saves. If local edits exist, Vitrine presents Reload and
    Keep instead of overwriting work. The watcher, permission, and source URL are never
    restored after the editor closes.
  • Comparison boards. Select two to four items from Recents in a visible order, then
    edit captions, details, item order, and Auto/Row/Column/Grid layout in a dedicated
    editor. Copy, save, or share the final board; its temporary draft retains rendered
    pixels rather than source paths or capture-history references.
  • A dedicated CLI documentation site. The new bilingual /cli page explains
    installation, licensing, every command, practical Git/terminal/recipe/batch workflows,
    common workarounds, and the complete searchable option catalog with copyable examples.

Changed

  • The README now teaches the CLI by intent. Installation channels, the PRO boundary,
    a first render, the command model, and everyday recipes now come before the full web
    reference instead of presenting newcomers with one uninterrupted flag catalog.
  • New workflows have real visual evidence. README and the website show real-build
    screenshots of living-file conflict handling, explicit recipe inspection and local
    folder association, ordered comparison selection, and the comparison-board editor.
  • Public product claims match the shipped boundaries. The documented language count,
    URL versus pasted-HTML behavior, network use, direct-download CLI installation, PRO
    price, and channel differences now align with the current build.

Fixed

  • Comparison previews cannot remain stuck on an indeterminate spinner. Rendering,
    ready, invalid, and failed states are explicit, and a compositor failure now produces
    a localized error while preserving the last good preview when appropriate.
  • Comparison export quality is stable across formats. PNG, HEIC, AVIF, and raster-PDF
    encoding share one exporter and honor the scale captured by the board draft instead of
    silently drifting with later app settings.
  • Recipe diagnostics point to the actual invalid field. A strict structural pass
    rejects unknown keys with complete paths while typed decoding keeps actionable enum and
    value failures.
  • Visual tours remain opt-in. Screenshot UI tests skip when no destination directory
    is supplied, preventing release and PR CI from accidentally executing evidence tours.

Security

  • Workspace recipes exclude file-system paths, credentials, capture history, and output
    destinations by construction; custom themes remain embedded portable values.
  • Local folder associations are stored separately as read-only security-scoped bookmarks,
    and recipe application never performs implicit discovery or repository scanning.
  • Comparison drafts and living snapshots remain window-scoped, with no persistent source
    reference after their owning window closes.

v0.25.5

Choose a tag to compare

@github-actions github-actions released this 01 Aug 13:28
Immutable release. Only release title and notes can be modified.
8b5ca99

What's Changed

Full Changelog: v0.25.4...v0.25.5

v0.25.4

Choose a tag to compare

@github-actions github-actions released this 28 Jul 01:15
Immutable release. Only release title and notes can be modified.
ddb00b7

What's Changed

Full Changelog: v0.25.3...v0.25.4

v0.25.3

Choose a tag to compare

@github-actions github-actions released this 26 Jul 16:21
Immutable release. Only release title and notes can be modified.
863dba7

What's Changed

Full Changelog: v0.25.2...v0.25.3

v0.25.2

Choose a tag to compare

@github-actions github-actions released this 26 Jul 03:01
Immutable release. Only release title and notes can be modified.
c061970

What's Changed

Full Changelog: v0.25.1...v0.25.2

v0.25.1

Choose a tag to compare

@github-actions github-actions released this 26 Jul 00:46
Immutable release. Only release title and notes can be modified.
63163a6

What's Changed

Full Changelog: v0.25.0...v0.25.1