CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Purpose

Mater is a static publication exploring materials through the eyes of artists and researchers. It is a deliberately low-carbon website — every technical decision should support that goal.

Commands

npm run serve   # Start local dev server with hot-reload
npm run build   # Build static site to _site/

No test suite is configured.

Environment Setup

No environment variables required. Content is stored as Markdown files in content/ and read at build time — no external CMS credentials needed.

Low-Carbon Principles

This project is built to minimise its environmental impact. All changes must preserve or improve on these constraints:

Architecture

Eleventy (11ty) static site with content managed via PagesCMS. Content lives as Markdown files with YAML frontmatter in content/ and is read at build time using gray-matter + fast-glob.

Data Flow

content/**/*.md files (YAML frontmatter) → _data/*.js reads them with gray-matter → Liquid templates consume the data → Eleventy outputs _site/.

Content pages (content/glossary/, etc.) are processed directly by Eleventy — their .md files carry their own layout and permalink frontmatter. content/about/ and content/announcement/ produce no pages of their own; they render into the About page (/about/) and the home page respectively.

content/glossary-words/ and content/reading-list/ items are tagged as Eleventy collections (glossaryWords, readingList) and rendered into the glossary page — they don’t produce their own output pages.

Key Config: .eleventy.js

The main Eleventy config (~240 lines) contains:

Content Directory

content/
  about/          # One .md per page on /about/ (title/order/body; no output pages of their own)
  announcement/   # Optional homepage announcement banner (no output page)
  contributors/   # Issue One contributor pages
  glossary/       # Glossary page content
  glossary-words/ # Individual glossary entries (no output pages)
  reading-list/   # Reading list entries (no output pages)
  references/     # References/materials entries
  stories/        # Story pages

New pages are created as About pages in this section (managed in PagesCMS); there is no separate footer-pages collection. The footer is a fixed set of links matching the nav (Mater, About, Stories, Texts, Podcast) plus a back-to-top arrow and the carbon badge, and is not rendered on the home page. The central nav is Material Archive, Stories, Texts, Podcast, About; Search sits alone in the top-right corner (both desktop and mobile).

Templates

Root-level .liquid files are pages; _includes/ contains layout and shared components:

File Route Notes
index.liquid / Home — contributor cards + story grid
about.liquid /about/ About page — white, :target-switched panels from content/about/
stories.liquid /stories/ Story listing grid
categories.liquid /categories/ Categories index
categories-category.liquid /categories/{slug}/ Per-category story listing
chapterone.liquid /chapterone/ Issue One contributor archive
landing-page.liquid Deprecated landing page
robots.liquid /robots.txt Allows all crawlers
sitemap.liquid Sitemap Auto-generated
_includes/layout.liquid Main HTML wrapper; inlines all CSS
_includes/stories-story.liquid /stories/{slug}/ Individual story; scroll colour animation
_includes/chapterone-stories.liquid /chapterone/{slug}/ Individual contributor page; scroll colour animation

Layout assignment for content/ files is handled by eleventyComputed in .eleventy.js, not by template frontmatter in the files themselves.

Colour System

14 named colours are defined in .eleventy.js (COLOURS / COLOURS_BG objects) and exposed via lookUpColour / lookUpColourBackground filters. Colour names come from content frontmatter fields:

purple, blue, rose, red, mud, ochre, moss, grass, jade, sea, midnight, amythyst, forest, grey

The CSS :has() pseudo-class in storycolors.css changes section backgrounds on hover — no JavaScript required.

Styling

Plain CSS, no framework. All files live in _includes/ and are inlined at build time:

Static Assets

src/assets/ is copied verbatim to build output. Contains logo, favicon, background images, uploaded content images, and the Arts Council England logo. src/_redirects is a Netlify redirects file.

Image Optimization

Images are resized on Cloudflare’s edge at request time via Image Transformations, not during the build. An Eleventy transform (imageCdn in .eleventy.js) rewrites every <img src="/src/assets/uploads/..."> in the output HTML to a /cdn-cgi/image/width=…,fit=scale-down,quality=82,format=auto/... URL. Templates choose a size with a data-img-width attribute on the <img> (thumbs 240, cards 600, heroes/lightboxes 1200; unmarked body images default to 1000); the attribute is stripped from the output.

The same transform also (in every environment, not just production):

The rewrite only runs when CF_PAGES_BRANCH=main (Cloudflare Pages production builds), because /cdn-cgi/image/ only resolves on the custom domain (mater.digital) — *.pages.dev previews and local dev serve the raw originals. Transformations must be enabled once per zone in the Cloudflare dashboard (Images → Transformations). format=auto delivers AVIF or WebP per browser and counts as one unique transformation; the free tier allows 5,000 unique transformations per month and the site currently uses ~600. Builds consume none — a build only writes URLs.

Deployment

Hosted on Cloudflare Pages. Build output is _site/. Redirects are in src/_redirects.