Build RelayThat

KINDAback to the verdict

0%0 of 17 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

A local brand design tool whose hard problems are one layout resolving correctly into a dozen aspect ratios, text and fonts that render identically on two machines, and exports whose pixel dimensions are the ones you asked for.

estimated effort weekendthe files for this build are in the project pack

ShellTauri 2 with React and TypeScriptLayoutSlots anchored to a per-size safe area, never coordinates multiplied by a scale factorRenderingOne renderer for both the preview and the export, run at the export's real pixel sizeTextFont files loaded by path, measured by the same engine that draws themStorageSQLite beside a folder of fonts and assets, with a manifest written per render

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. installfree

    Why Tauri 2 needs both, and the desktop shell is what gives you the font folder and the export folder.

    Get it nodejs.org and rustup.rs, then the Tauri prerequisites for your platform. open ↗

    Verify node --version prints v22 or higher and cargo --version succeeds

  2. have readyfree for open licensed families, otherwise whatever you paid

    Why The whole rendering model loads faces by file, and the licence of each face decides whether it may travel in an export.

    Get it Your own purchased faces, or open licensed families whose licence text you have actually read.

    Verify Every face in the folder has a recorded licence name and a redistributable flag

  3. have readyfree

    Why Contrast over a photograph behaves nothing like contrast over a flat colour, and it is the case that breaks first.

    Get it Export your logo with transparency at a generous size, and pick two photographs with busy areas.

    Verify A headline over the busy photograph is flagged at some sizes and not others

  4. have readyfree

    Why The minimum ratio is copied from published guidance rather than chosen, and it differs by text size.

    Get it Read the current accessibility guidance for contrast, note the ratios and the date, and record both in your configuration. open ↗

    Verify A note records the ratios used and the guidance version

  5. have readyfree

    Why The export dimension bug only appears when the display scale factor differs from one, and it is the most common way a render comes out the wrong size.

    Get it A laptop with a high density panel plus any ordinary external monitor.

    Verify The same export produces identical dimensions on both

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

- brands(id, name, version, palette_json, logo_asset_ids, font_ids, created_at) · versioned, because a render has to say which brand it used
- fonts(id, family, style, file_path, licence_name, licence_url, redistributable, added_at) · the licence is recorded per face, not per project
- assets(id, kind, path, width, height, sha256, has_alpha) · logos and photographs copied in, never referenced from somewhere else on disk
- sizes(id, name, width_px, height_px, safe_top, safe_right, safe_bottom, safe_left) · every output shape carries its own safe area
- layouts(id, name, version, slots_json) · a slot has an anchor, a minimum and maximum type size, and a stated behaviour when the text still does not fit
- designs(id, brand_id, layout_id, headline, subhead, call_to_action, asset_ids_json)
- renders(id, design_id, size_id, path, manifest_json, rendered_at) · the manifest holds font ids, asset hashes, brand version and layout version
- A design is stored once; a render is a design plus a size plus the manifest that lets you rebuild that exact file a year later.

Environment variables

These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.

VariableNeededExampleWhere the value comes from
DATA_DIRrequired~/.local/share/brandkitSQLite plus the copied assets. Back it up with the fonts folder.
FONTS_DIRrequired~/.local/share/brandkit/fontsFont files loaded by path. Each face records its licence.
EXPORT_DIRrequired~/Pictures/brandkit-exportsRenders and their manifests, side by side.
EXPORT_RETENTION_DAYSrequired180How long renders are kept. Manifests let you rebuild after that.
MAX_RENDER_PIXELSrequired40000000A ceiling on width times height, so a mistyped size cannot exhaust memory.

The build, in order

  1. One design, many shapes

    A design laid out once renders into a wide, a square and a tall size without anything falling off the canvas.

    1. The safe area is what the layout anchors to, so it is part of the size definition.

      Files src/sizes.tssrc/layout/anchors.ts

    2. Scaling is the bug this whole phase exists to avoid.

      Files src/layout/resolve.tssrc/layout/resolve.test.ts

    3. A bounding box check catches the failure the eye misses at thumbnail size.

      Files tests/safe-area.test.ts

    done when · tick each as it passes
    watch out
    • Producing the other sizes by multiplying the square design's coordinates by a scale factor pushes the headline off a tall canvas and drops the call to action to nine pixels on a wide banner, and both look acceptable in a thumbnail. Anchor each slot to the target size's safe area and resolve its type size for that size alone.
  2. Fonts that render the same on two machines

    Type is drawn from a font file you hold, with its licence recorded, and a missing face fails loudly.

    1. The licence belongs to the face, and you will want it when you export a kit.

      Files src/fonts/registry.tssrc/fonts/licence.ts

    2. Any other measurement is an estimate that diverges on the long strings.

      Files src/text/measure.tssrc/text/measure.test.ts

    3. A silent fallback is a wrong export you will ship.

      Files src/fonts/registry.tstests/missing-face.test.ts

    done when · tick each as it passes
    watch out
    • Naming a font family and letting the system pick means the machine without that family quietly substitutes a fallback, so the same design exports with different line breaks on your laptop and on the machine you render the batch from, and nobody notices until a headline wraps onto three lines in the one size you did not check. Load the file, measure with the engine that draws, and treat a missing face as a failure.
  3. Text that fits and colour you can read

    Long copy on a narrow size fails visibly rather than exporting something unreadable.

    1. A readable failure beats an unreadable export.

      Files src/text/autofit.tssrc/text/autofit.test.ts

    2. The crop changes per aspect ratio, so the background does too.

      Files src/contrast/sample.ts

    3. Copied from the current guidance, with the date, not invented.

      Files src/contrast/thresholds.tsdocs/contrast.md

    done when · tick each as it passes
    watch out
    • Shrinking type until the copy fits gives you a six point headline on the tall size, and clipping gives you a caption that ends mid-word, and both export without complaint because the code only asked whether the text fitted. Set a floor, and when the copy still does not fit, fail that render with the size name and the character count so the copy gets shortened instead.
    • Contrast checked once against the brand's background colour passes, then the same headline goes over a photograph and becomes invisible on half the sizes because the crop differs per aspect ratio. Sample what is actually behind the text at each size.
  4. Exports at the size you asked for

    A file requested at 1080 by 1080 is 1080 by 1080 on every display.

    1. The display's scale factor must not reach the output.

      Files src/render/offscreen.ts

    2. Read the file back; do not trust the call that wrote it.

      Files tests/export-size.test.ts

    3. A failed size should not leave half a PNG in the folder.

      Files src/render/batch.ts

    done when · tick each as it passes
    watch out
    • Exporting by reading pixels back from the canvas that is on screen gives you a file at the display's device pixel ratio, so the same button produces a 2160 pixel square on a high density laptop and a 1080 pixel one on an external monitor, and the platform rejects one of them. Render off-screen at the requested dimensions and assert the written file's size.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more design.