A Quarto website at haigh.bio, deployed to GitHub Pages.
Each page is a directory containing index.qmd, which renders to <dir>/index.html and is
served at the clean URL <dir>/ (see bin/clean-urls.sh).
.
├── _quarto.yml # site config (title, nav, theme)
├── _quarto-production.yml # production profile — excludes drafts + hidden from deploy
├── index.qmd # home page
├── about/index.qmd # about page
├── blog/
│ ├── index.qmd # blog listing (auto-generated from posts/)
│ ├── posts/ # published posts (one folder per post)
│ │ ├── _metadata.yml # defaults applied to every post (incl. giscus comments)
│ │ └── <slug>/index.qmd
│ └── drafts/ # WIP posts — excluded from production render
│ ├── _metadata.yml
│ └── <slug>/index.qmd
├── hidden/ # unlisted pages — excluded from production render
├── projects/index.qmd # projects & decks page
├── personal/index.qmd # ceramics + photography galleries (draft)
├── life/index.qmd # Game of Life (canvas) easter egg
├── reaction-diffusion/index.qmd# Gray-Scott reaction-diffusion (WebGL) easter egg
├── decks/ # Reveal.js deck sources + exported PDF/PPTX
│ └── <slug>/index.qmd
├── img/ # gallery images for the Personal page
│ ├── ceramics/ # square images, 3-col grid
│ └── photo/ # 3:2 landscape, 2-col grid
├── bin/ # build helpers (new-post.sh, clean-urls.sh)
├── styles.css # site CSS tweaks
└── .github/workflows/
├── publish.yml # auto-deploy on push to main
└── check.yml # render check on pull requests
- Install Quarto:
brew install --cask quarto(or download from quarto.org) - (Optional) For a better editor experience, use VS Code with the Quarto extension.
- Install the lightbox extension (powers click-to-zoom on the Personal page):
This creates an
quarto add quarto-ext/lightbox
_extensions/directory which should be committed.
quarto previewThis includes draft posts and hidden pages and opens a live-reloading preview at
http://localhost:4242.
quarto render # all pages (local)
quarto render --profile production # production targets only (matches CI)Output goes to _site/.
Pushes to main trigger .github/workflows/publish.yml, which renders the site (excluding
blog/drafts/ and hidden/) and publishes to the gh-pages branch. Pull requests run
.github/workflows/check.yml, which renders the same production targets without publishing.
- Create a new repo on GitHub (public, or private with GitHub Pro for Pages on private).
- Initialise and push:
git init git add . git commit -m "Initial scaffold" git branch -M main git remote add origin https://github.com/stevehaigh/quarto-site-builder.git git push -u origin main
- Create an empty
gh-pagesbranch (the workflow needs it to exist):git checkout --orphan gh-pages git reset --hard git commit --allow-empty -m "Initialise gh-pages" git push origin gh-pages git checkout main - In GitHub: Settings → Pages → Build and deployment
- Source: Deploy from a branch
- Branch:
gh-pages// (root)
- Push to
main— the publish workflow renders and deploys.
The site is live at haigh.bio (GitHub Pages default URL:
https://stevehaigh.github.io/quarto-site-builder/).
- Register the domain at Cloudflare Registrar (at-cost pricing).
- In Cloudflare DNS, add records pointing to GitHub Pages:
- For an apex domain (
example.com), add four A records to:(set proxy status to DNS only — grey cloud — to avoid HTTPS cert issues with GitHub Pages)185.199.108.153 185.199.109.153 185.199.110.153 185.199.111.153 - For
www, add a CNAME pointing tostevehaigh.github.io.
- For an apex domain (
- In GitHub: Settings → Pages → Custom domain, enter your domain. GitHub will create a
CNAMEfile in thegh-pagesbranch and provision an HTTPS cert (takes a few minutes). - Tick Enforce HTTPS once the cert is issued.
- Update
site-urlin_quarto.ymlto your new domain.
bin/new-post.sh my-new-post "My new post" # scaffolds blog/drafts/my-new-post/index.qmd
quarto preview # drafts are included in local preview
$EDITOR blog/drafts/my-new-post/index.qmdWhen ready to publish:
- Move the folder from
blog/drafts/<slug>/toblog/posts/<slug>/. - Remove
draft: truefrom the front matter. - Push to
main— the site rebuilds.
Draft and hidden pages are excluded from production render, search, listings, and sitemap.
- Create a Reveal.js deck source at
decks/<slug>/index.qmd(see existing decks for examples). - Build HTML, PPTX, and PDF locally:
PDF export uses headless Chrome locally; commit the generated PDF so CI can deploy it.
decks/<slug>/build.sh
- Add links in
projects/index.qmd. - Commit and push.
The personal/index.qmd page currently references placeholder SVGs in img/ceramics/ and img/photo/, and is marked draft: true. To add your own work:
- Drop your images into the relevant folder (
img/ceramics/orimg/photo/). See theREADME.mdin each folder for size/format guidance. - Update the image references in
personal/index.qmd— changeplaceholder-01.svgto your filename (and remove placeholder files you no longer need). - Remove
draft: truefrom the front matter to publish the page. - Commit and push.
The lightbox extension (installed in one-time setup) gives each image click-to-zoom for free. Captions from the Markdown  syntax appear under the zoomed image.