Skip to content
New: Customize your theme with an AI assistant. Read the guide

Projects, Photo Series & Archive

Files: src/content/projects/<language>/ (one file per project, plus -index.md), src/content/pages/<language>/archive.mdx · Skill level: Beginner

Your work lives in one collection: src/content/projects/. Each file is one project page at /projects/<file name>/. A project can be a case study, a split case with the facts beside the images, or a photo series. The same entries fill the projects list at /projects/, the archive at /archive/, the projects sections on the homepages, and the next-project link at the end of each project page.

The demo ships 12 projects: 4 case studies, 2 split cases, and 6 photo series. Replace them with your own work before launch.

Pick A Template

The options.layout value at the end of the frontmatter picks the page template. Every template reads the same fields.

options:
layout: "default" # default | gallery | split
TemplateWhat the page showsDemo example
defaultA case study: page header with the facts, the cover across the page, the text, the figures, the image blocks, the client quoteceramic-forms.md
splitOn large screens, a sticky column with the title, description, and facts beside one column of images. Then the text, figures, and quotegift-bag.md
galleryA photo series: page header with the place, year, and number of photos, then every image in a masonry grid that opens a lightbox, then the textnorth-atlantic.md

All three end with a link to the next project and the call to action. Case studies and split cases also show the client logos.

Add A Project

  1. Copy the demo entry that matches your template, for example src/content/projects/english/ceramic-forms.md.

  2. Rename the copy. The file name becomes the URL (/projects/my-project/) and the project’s id, which other files use to point to it.

  3. Put the images in their own folder, for example src/assets/images/projects/my-project/. In content files, write the path from /images/: /images/projects/my-project/cover.jpg.

  4. Change the frontmatter values and the Markdown body. Keep the keys.

  5. Add the same file name in src/content/projects/french/ and src/content/projects/arabic/, with the translated text and the same image paths.

To hide a project, set draft: true. It still shows in npm run dev, but it is left out of the built site and every list.

Project Fields

title, description, image, draft, and the SEO fields work as on every page (Pages). ceramic-forms.md shows every field with a comment.

FieldWhat it does
imageThe cover, 4:3. Also the project card
imageAltDescribes the cover for screen readers
clientThe client’s name, in the facts strip. A case study’s title is usually the client’s name
yearText, so a range such as "2023–2024" works
role, servicesYour role, and a list of services, in the facts strip
durationHow long the project took, in the facts strip
locationFor a photo series: where the photos were taken
informationExtra rows for the facts strip: - label: "Printing" / value: "One-colour labels"
liveUrlAdds a “Visit site” link. Empty hides it
categoriesThe filter chips on /projects/ and /archive/. Use the same spelling in every entry of a language
tagsKeywords for search engines. They are not shown on the page
resultOne line about the outcome. The subtitle in the index and stack list layouts
metrics2 or 3 figures in a band: - value: "40" / label: "Glazes on one layout". Write the final text; the figure counts up
quoteA client quote: text, emphasis (a part of text, copied exactly, set in a heavier weight), name, role, and image (a square portrait, or "")
imagesThe image, video, and text blocks of the page, in order (below)
nextThe id of the next project. Empty: the next one of the same kind by weight, back to the first after the last
featuredtrue or false. The project card in the Services menu uses the first project with featured: true when its cta.project is empty (see Navigation). The demo names ceramic-forms there, so featured changes nothing until you empty it
weightThe order in every list, lowest first. Entries without a weight go last
options.layoutThe template: default, gallery, or split

The Markdown body (## Overview, ## Approach, ## Result in the demo) is the case study text. A photo series can have a short body too.

related takes a list of project ids. The project pages in this version don’t show it.

Image Blocks

images is the list of blocks on the page, in order. Each block has a type and a size.

images:
- type: "image"
src: "/images/projects/my-project/gallery-1.jpg"
alt: "Describe what is visible, for screen readers."
caption: "Optional line under the image and in the lightbox."
size: "full"
- type: "video"
src: "/videos/my-project.mp4" # a file in public/ or a full URL
alt: "What the video shows."
poster: "/images/projects/my-project/poster.jpg"
size: "half"
- type: "text"
title: "One grid, forty names"
body: "A short paragraph in **Markdown**."
size: "half"
typeNeedsWhat it shows
imagesrc, altA framed image that opens the lightbox. image is the default when type is left out
videosrc, altA muted, looping video that plays while it is on screen, with the browser’s controls. poster is the still shown first
textbodyA short heading (title) and a paragraph
sizeWidth
fullAcross the page, 3:2 (the default)
halfTwo in a row, 4:3
thirdThree in a row, 4:5

Phones show every block at full width. In the split template the images stack in one column, each in its own shape. In the gallery template every image is part of the masonry grid. Videos don’t start on their own for visitors who turn on reduce motion in their device settings.

npm run astro-check reports an image or video block without src or alt, and a text block without body.

The Projects Page

/projects/ takes its page header, layout, and options from src/content/projects/<language>/-index.md:

projectsSection:
options:
layout: "grid" # grid | index | wall | stack
category: "" # one category, or empty for all
items: [] # project ids in order; overrides `category`
limit: 0 # at most this many (0 = all)
filters: true # `grid` and `index`: category chips above the list

With filters: true, an “All” chip and one chip per category appear above the cards. The address keeps the chosen chip, such as /projects/#branding, so you can link to a filtered list. The page also shows the logos section (logosSection) and the call to action (ctaSection). For each layout, see Section Layouts.

The Archive

/archive/ lists every project as ruled rows, newest first: year, title, result, client, and services. Moving the mouse over a row shows its cover beside the pointer. Its file is src/content/pages/<language>/archive.mdx:

projectsSection:
options:
layout: "index"
order: "year" # year (newest first) | weight
filters: true

A photo series without a client reads “Personal series” in the client column.

Projects On Other Pages

Any page can show projects with a projectsSection: block, using the same options. The homepages use it with items to pick projects by id, and the studio homepage with the index layout. The hero stack and masthead layouts show a deck of projects from the hero’s cards list, and a gallery section can show the images of one photo series with options.project. See Homepages.

The link at the end of each project page is the next-project section, src/content/sections/<language>/next-project-section.md. Its layout is banner (one large link) or cards (the previous and next projects). label and seriesLabel are the small labels above the title, for a case study and a photo series. A project file can change them for its own page with a nextProjectSection: block.

Do It With AI

Add a [case study | split case | photo series] to src/content/projects/english/ called [NAME].
Copy the frontmatter of [ceramic-forms.md | gift-bag.md | north-atlantic.md], keep its comments,
and set options.layout to [default | split | gallery]. Use these facts: [CLIENT, YEAR, ROLE,
SERVICES, CATEGORIES]. My images are in src/assets/images/projects/[NAME]/; write alt text for
each and use paths starting with /images/. Write the body from these notes: [NOTES]. Then create
the french and arabic versions with the same file name, and run npm run astro-check.
Type something to search...