Skip to main content
Hagaki Renderer is a purpose-built asset rendering service for card game applications. It accepts a base64-encoded JSON payload over HTTP and returns a PNG image — either freshly rendered or served from disk cache — in a single round trip.

Quickstart

Make your first render request in minutes.

API reference

Full endpoint and parameter documentation.

Deployment

Build and run Hagaki on Linux, systemd, Docker, or behind Nginx.

Core concepts

Hash encoding, frame types, the dye system, and caching.

What Hagaki does

Hagaki exposes three HTTP endpoints. Each accepts a base64-encoded JSON hash that fully describes the render payload and returns an image/png response.
EndpointDescription
GET /render/card/{hash}Render a single card at 550×800 px.
GET /render/fan/{hash}Composite multiple cards into a fanned spread.
GET /render/album/{hash}Composite multiple cards into a padded grid.

Key features

Oklab dye blending

Cards are colorized using the perceptually-uniform Oklab color space for accurate, vibrant hue shifts that match human vision.

Parallel rendering

Fan and album renders use Rayon for multi-core parallelism — all cards in a batch render simultaneously across available CPU cores.

Disk caching

Set a save_name in your payload and Hagaki persists the render to disk, serving it instantly on repeat requests with no re-render cost.

In-memory frame cache

Frame overlay assets are loaded once at startup and shared across all requests via Arc, eliminating repeated disk I/O per request.

Reproducible renders

The same hash always produces the same image, making HTTP-level caching trivial to implement upstream of the service.

Observability headers

Every response includes X-Source (cache hit vs. fresh render) and X-Processing-Time measured in milliseconds.

How it works

1

Construct a JSON payload

Your client builds a JSON object describing the card or cards to render — including the character ID, frame type, dye value, and optional position offsets.
2

Encode the payload as a hash

Serialize the JSON to a string and encode it as standard base64 (no padding). This hash becomes the final segment of the request URL and fully identifies the render.
3

Send a GET request

Make a GET request to the appropriate /render/* endpoint. No request body, no authentication headers — just the hash in the path.
4

Receive the PNG

Hagaki decodes the hash, checks disk cache if save_name was provided, composites the image using layered rendering, and returns PNG bytes with timing and source headers.

Frame types

Hagaki ships with three built-in frame styles. Each has different capabilities for static models, dye color support, and extendability.
Frame typeIDDye supportStatic modelExtendable
Moonweaver0YesYesYes
Essentia1YesNoNo
Snowglow2NoYesYes
All frames produce output at 550×800 px. Frames that support dye blending apply your dye value using Oklab color physics. Frames without dye support ignore the dye field.

Deployment and security

Hagaki has no built-in authentication layer. It is designed as an internal microservice. Always deploy it behind a reverse proxy such as Nginx and restrict access to trusted callers only.
The service binds to 0.0.0.0:8899 by default. Renders time out after 5 seconds — any request that exceeds this limit returns a 500 error rather than hanging indefinitely. Refer to the deployment guides for instructions on running Hagaki with systemd, Docker, or behind Nginx.

Build docs developers (and LLMs) love