Lyra Astro documentation

Colours, fonts and photos

Re-colour Lyra for your brand, change the heading font, and replace the placeholder images with your own photos.

How the colours work

Lyra’s colours come in three layers, all in src/styles/tokens/:

File What’s in it
colors.css The colour scales: clay (terracotta), leaf (green), sun (yellow), sky (blue), berry (pink), sand (warm greys) and red, each from 50 (lightest) to 950 (darkest).
theme.css What each colour is for: --brand, --accent, --highlight, the cause colours, text, surfaces and lines, each with a light-mode and a dark-mode value. Blocks only use these names.
scale.css Type sizes, spacing, corners, shadows and page width.

Every text and background pair meets the WCAG AA contrast standard in both light and dark mode.

Changing your brand colour

The quickest way is to point --brand at a different scale in theme.css. For a green brand with a terracotta accent, swap the two:

--brand: light-dark(var(--leaf-700), var(--leaf-400));
--accent: light-dark(var(--clay-600), var(--clay-400));

Change the -hover, -ink and -soft lines under each one the same way.

Your own colour scale

To match an exact brand colour, generate new scales:

  1. Open scripts/palette.mjs. Each scale at the top has a hue (0–360, the colour’s position on the colour wheel) and a chroma (how vivid it is, around 0.12–0.16).
  2. Change the clay hue to your brand’s. Terracotta is 42, red about 25, pink about 0, purple about 300, blue about 250, teal about 190 and green about 145.
  3. Run node scripts/palette.mjs. It prints the new colors.css and checks the contrast of every pair the theme uses.
  4. Paste the output into src/styles/tokens/colors.css.

Any online “hex to OKLCH” converter tells you your colour’s hue.

Section tones

The eight tones you can give a block (cream, blush, mint, sky, sand, brand, night and default) are at the bottom of theme.css. brand and night are dark: everything inside them, including buttons and cards, switches to its dark-mode colours.

Light and dark mode

The site follows each visitor’s system setting, and the moon button in the header lets them choose. Their choice is remembered on their device.

Heading font

Headings use Bricolage Grotesque, a warm, friendly sans-serif, through Astro’s built-in Fonts API. It’s one 41 KB file served from your own site, with no requests to Google, and a matched fallback stops text from jumping while it loads. Body text uses each device’s system font, which costs nothing to load.

To use a different font, install it from Fontsource:

npm install @fontsource-variable/fraunces

Then, in astro.config.mjs, change name and point src at the new font’s file in node_modules/@fontsource-variable/<font>/files/, usually the one ending latin-wght-normal.woff2. Fontsource lists other files for other alphabets, such as latin-ext or cyrillic.

The header and footer show a heart icon beside your organisation’s name. To use your own logo, replace the logo-mark icon and the name after it in src/components/Header.astro (two places: the header and the phone menu) and src/components/Footer.astro with an image, for example <img src="/logo.svg" alt="Your charity" width="140" height="40" />, and put the file in public/. Replace public/favicon.svg with your own icon too.

Photos

Photos live in src/assets/images/, and pages and content files refer to them by file name:

image: water-well.jpg
imageAlt: A girl washing her face at a village tap

Lyra resizes every photo when you build, converts it to AVIF and WebP, and gives each visitor only the size their screen needs, so you can upload large, good-quality JPGs straight from your camera or phone.

The placeholder images

The demo uses free-licence photos whose licences don’t allow passing them on, so the download replaces them with coloured placeholders. They’re drawn by scripts/placeholders.mjs before every npm run dev and npm run build, but only for file names that are missing: your own photos are never touched.

Replace them in either of two ways:

  • Same names. Save your photo as src/assets/images/water-well.jpg and it’s used everywhere the placeholder was.
  • New names. Add river-project.jpg and change image: in the pages that should use it.

Once you’ve replaced them all, you can delete the list in scripts/placeholders.mjs.

Good photo sizes

Where Shape At least
Hero (split variant) Portrait, about 4:5 1200 × 1500
Hero (overlay), page headers Landscape 2000 × 1200
Causes, campaigns, stories, events Landscape, 3:2 1600 × 1070
Team photos Square 600 × 600
Share image (shareImage) Landscape 1200 × 630

Choosing the crop

Page headers show a wide strip of the photo, centred. If heads are cut off, add imagePosition to the page header block or the cause, event or story file: top, center, bottom, or two percentages such as 50% 30% (across, then down).

Describing photos

Write a short imageAlt for every photo, describing what’s in it (“Children carrying water containers past the new well”). Screen readers read it aloud, and search engines use it. Describe the scene, and think about the dignity of the people shown.

Video

The video block plays a YouTube or Vimeo link, or your own file in public/, such as /media/film.mp4. Nothing is loaded from YouTube or Vimeo until the visitor clicks play. The demo clip isn’t included in the download; the block shows its poster photo until you add your own, and the build prints a reminder.

Page width and corners

--wrap in scale.css sets the content width (1200px), and --radius-s to --radius-xl set how rounded cards, buttons and photos are.