Three Cosy Releases in One Day: Signed URLs, SVG Output, 158 Templates

Three tags landed on Cosy in fifteen hours: signed GET URLs for og:image, self-contained SVG output, and six new social templates. The template count now stands at 158.

Three Cosy Releases in One Day: Signed URLs, SVG Output, 158 Templates

Three Cosy Releases in One Day: Signed URLs, SVG Output, 158 Templates

On September 29, three release tags landed on the Cosy repo within fifteen hours: v0.3.0 at 09:01 UTC, v0.4.0 at 11:25, and v0.5.0 at 23:20. Cosy is a template-based image renderer written in Rust. One small binary takes SVG templates plus JSON and returns finished PNGs in tens of milliseconds, with no browser in the rendering path. This batch of releases closes the gaps that kept it a fast renderer rather than a complete image service.

The integration gaps this batch closes

Until this week, Cosy rendered through one shape: a POST request with JSON, PNG bytes back. Fine for scripts and agents. Wrong for three common jobs. A blog engine's og:image tag wants a plain GET URL, not a client library. A design handoff wants vectors, not pixels. And a code screenshot meant wiring up headless Chromium, the exact dependency Cosy exists to avoid.

Signed GET URLs: og:image without a client (v0.3.0)

The headline feature is GET /r/{template}.png?d=<base64url JSON>&sig=<hmac-sha256>. A blog engine embeds one URL in its meta tags and Cosy renders on request, without a client library or POST plumbing.

The signature covers the template name and the data together, so a URL signed for one template cannot be replayed against another. Comparison runs in constant time, and the API key doubles as the signing key, so there is nothing extra to configure. When no key is set, the route answers 404 instead of serving an open renderer. Payloads above 8 KB get a 413, bad signatures get a 403, and responses carry Cache-Control: public, max-age=3600 so a CDN absorbs repeat renders.

CSV batch, WebP, and metadata passthrough (still v0.3.0)

cosy render --dataset rows.csv --out-dir out/ renders one image per CSV row in parallel on Rayon. Column headers map to template fields, an optional _filename column names each output, and --fail-fast stops the run after the first failure with exit code 1. Feeding it a spreadsheet of forty products returns forty branded images.

Output format also opened up in this release. WebP arrived on both the CLI (--format webp) and the API (image_format), chosen independently of the response envelope. An optional metadata field, any JSON value up to 4 KB, now rides along on a render request and comes back untouched in the JSON response, which makes it much easier to correlate renders with the job that asked for them.

SVG output: self-contained vectors (v0.4.0)

--format svg, or image_format: "svg" on the API, returns the resolved vector tree instead of rasterized pixels. Text is converted to paths during processing, so the file renders identically everywhere with zero font dependencies. This is the format design handoff wants: open it in any vector editor and edit.

One quirk to know: scale is a raster concept, so it is ignored in SVG mode and the canvas stays at 1x.

v0.5.0: code-screenshot and six social templates

code-screenshot draws a macOS editor window, traffic lights and filename badge included, with real syntax highlighting behind it. A new highlight module tokenizes keywords per language (Rust, Go, Python, TypeScript, JavaScript, Bash, SQL), plus strings, numbers, and comments, on both dark and light themes, at 1200x675. Before this template, that image class required a browser.

Six social templates joined the library: tweet-screenshot, linkedin-text-post, testimonial-card with an SVG star rating, audiogram-card with a static waveform, meme-text-card, and sparkline-card with a gradient area fill. The template count now stands at 158.

SVG output also gained semantic structure in this release: field content is wrapped in groups like id="f-author", preserved through the processing pipeline, so downstream tooling can target individual elements. og-image and code-screenshot carry it first, and the convention is now required for new templates. A markup fix in the same release stops bold and italic emphasis from being dropped in multi-line fields.

What it adds up to

One binary now answers four call patterns: CLI, POST API, signed GET URLs, and CSV batch rendering. Screens get PNG or WebP, design gets SVG, and og:image tags get a plain URL they can embed forever.

An honest maturity note, since this blog holds itself to that standard: Cosy is a young project with a small user base, and it is licensed under BSL 1.1, which converts to Apache 2.0 in 2029. You are reading release notes for a v0.x tool, not an enterprise platform.

To try it: prebuilt binaries for macOS (Apple silicon), Linux (x64 and arm64), and Windows are on the v0.5.0 release page, with a SHA256SUMS file to verify them. Docker users can pull ghcr.io/codecoradev/cosy:latest. Building from source is cargo build --release.

For the architecture of the renderer and a five-minute setup walkthrough, we published those separately: Self-Hosted OG Image API in Pure Rust covers the design, and Getting Started with Cosy covers the first render.