coppice

command module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 30, 2026 License: GPL-3.0 Imports: 43 Imported by: 0

README

coppice

coppice builds a small personal site with essays from markdown: one Go program, markdown in, static HTML out, no framework, no Node. A mathematical animation on the home page (ASCII shapes, Lissajous figures, cycloids, the Mandelbrot set's boundary), Tufte-style sidenotes in posts, a list of writings by year, galleries, a docs section with search, an RSS feed and a sitemap, colour themes with a dark side, highlighted code, and self-hosted fonts from Google Fonts.

It is free software under the GPL v3 (see Licence).

A site of your own

You need Go 1.25 or newer. coppice works as Jekyll does: your site is a folder, or a repository, of its own, and coppice is run in it. Its look, the templates, the stylesheet and the scripts, is built into the program.

go run github.com/obk/coppice@latest -new mysite
cd mysite
go run github.com/obk/coppice@latest -serve :8000

or go install github.com/obk/coppice@latest once, then coppice -new mysite, coppice and coppice -serve :8000.

-new writes a config.toml with every setting explained, a home page, a contact page, a first post, an icon and a README. A site can change any part of the look with files of its own: a template in templates/, a stylesheet in styles/, anything in static/ (Customising).

Or start from this example

This repository is also coppice's example site, with every feature at work: three posts, a gallery and coppice's docs.

  1. Fork or clone this repository.

  2. Edit config.toml: the site's name, URL, description, the links on the home page, the animation, colours, fonts, analytics (or none), and the site's own words for a site in another language.

  3. Make the content yours: content/index.md is the home page's text, any other content/<name>.md a page at /<name>/, posts go in content/posts/ and docs in content/docs/. The examples (an about page, a gallery of 118 public-domain paintings in static/images/gallery/ (34 MB), three posts, and coppice's own docs) are there to read and delete.

  4. Build and look:

    go run .                    # build into public/
    go run . -serve :8000       # build, serve on http://localhost:8000,
                                # and build again whenever a file changes
    go run . -serve :8000 -drafts   # with drafts and later posts too
    

    The first build downloads the fonts, so it needs the internet; they're cached in .cache/fonts/ after that.

Docs

The full documentation is coppice's own docs section, which the example site builds at /docs/. Its sources read well here too:

Deploy

public/ is the whole site: upload it to any static host. On a host that builds from git, such as Cloudflare Pages, make go run . the build command and public the output directory, and set the environment variable GO_VERSION to 1.25 or newer; for a site in a repository of its own, the build command is go run github.com/obk/coppice@latest. See Deploying.

How it's put together

main.go      the generator: Markdown, sidenotes, galleries, feed, sitemap, checks
fonts.go     downloads the fonts from Google Fonts at build time
templates/   the theme: base.html wraps every page; one template per page type
styles/      the theme: the stylesheet in parts, joined into css/site.css
static/js/   the theme: the animations' and pages' scripts
starter/     what -new writes
config.toml  the example site's settings
content/     the example site: index.md, a .md file per page, posts/, docs/
static/      the example site's pictures, copied as they are
tools/gifs/  records the animations as GIFs for this README (own module)
docs/        those GIFs; not part of the site
url source template
/ index.md index.html
/posts/<slug>/ posts/<slug>.md post.html
/writings/ all posts, grouped by year writings.html
/feed.xml all posts, full text (RSS 2.0) (in main.go)
/docs/<slug>/ docs/<slug>.md doc.html
/docs/ docs/index.md and every doc docs.html
/<name>/ <name>.md, e.g. contact page.html
/404.html (none) 404.html
/sitemap.xml, /robots.txt every page but the 404 (in main.go)

The theme (templates/, styles/, static/js/) is built into the program; the example site, here, has it as its own files too, so a change to it shows at once with go run . -serve :8000. go test ./... runs the tests, and builds this example site, a new one from -new, and one with nothing but the built-in theme, checking every link in them.

Animations
shapes
shapescurve
curvecycloid
cycloidmandelbrot
mandelbrotcycloid-horizontal
cycloid-horizontalford
fordgolden
goldennautilus
nautilussine
sinepenrose
penrosechords
chordsnewton
newton

The GIFs are recorded from the real scripts by tools/gifs; after changing an animation, run go -C tools/gifs run . (or name the ones to redo: go -C tools/gifs run . golden).

Set animation in config.toml. Each is one script in static/js/, named after it; a page loads only the one it shows, through loop.js, which pauses it off screen, shows a still frame to people who ask for reduced motion, and carries the animation over from home to contact so it doesn't restart. Without JavaScript they're hidden; the site works without it.

  • shapes: a donut, cube, octahedron, Menger sponge, dodecahedron, gyroid and Hopf link in ASCII, after donut.c. Each character raymarches a signed distance field; a morph blends two fields, so shapes melt into each other.
  • curve: a dot stretches into a line that opens into a Lissajous figure, then loops through Lissajous figures and rose curves. Every curve has the same 1200 points, so a morph moves each point to its partner.
  • cycloid: a circle rolls round a fixed one and its pen draws a cardioid, nephroid, epicycloid, deltoid, astroid and hypocycloid.
  • mandelbrot: the curves |z_n(c)| = 2 for n = 2 to 10 and back, closing in on the Mandelbrot set's boundary. Each is traced in the browser by following z_n(c) = 2·e^(i·2^(n-1)·θ) round in small steps; θ is the same "external angle" on every curve, so a morph moves each point a short way.
  • cycloid-horizontal: a circle rolls along a line, end to end and back, never stopping; from edge to edge its pen slides along the spoke, drawing normal, curtate and prolate (looped) cycloids.
  • medley: curve, cycloid and cycloid-horizontal as one, with one line throughout. The last rose becomes a cardioid as the circles fade in; later the fixed circle unrolls into a line and the curve into the trail of a circle rolling along it (a cycloid is an epicycloid round an infinitely large circle); then the trail closes back into the first Lissajous figure. Every change blends the same points, so nothing cuts.
  • ford: Ford circles. Over every fraction p/q between 0 and 1, in lowest terms, a circle of radius 1/(2q²) resting on a line; no two overlap, and neighbours in a Farey sequence touch. The two big ones over 0 and 1 rise first, then each denominator up to 20, smaller and quicker; they hold, then sink back, smallest first.
  • golden: a dot stretches into a line, which curls up into the golden spiral (a logarithmic spiral widening by φ every quarter turn), holds, then uncurls back to the dot. The line bends but never stretches: each stage is the same line partly rolled up.
  • nautilus: a nautilus shell in section. The line curls as in golden, but into a spiral widening 3 times a turn, close to a real nautilus; then the mouth closes it and the septa, the curved walls between its chambers, grow in from the innermost out, leaving the last third of a turn open as the body chamber.
  • sine: a dot stretches into a line; then a pen at its left end bobs up and down, speeding up from rest, and its height, carried off to the right at a steady speed, draws a sine wave that runs out along the flat line until it fills it.
  • penrose: the Penrose triangle, the impossible one: three square beams at right angles in a loop. It starts to turn, slowly, and turns for ever; every third of a turn it looks as it began. It's three faces of real beams seen isometrically, each a third of a turn from the next.
  • chords: N points round a circle, each joined to the point k times as far round. The chords' envelope is a cardioid for k = 2, a nephroid for 3, then epicycloids; the chords are drawn in one by one, then k counts up to 6, the chords sliding from curve to curve, and back.
  • newton: Newton's cradle. The first ball is lifted and let go; it stops dead as it hits the row and the last one swings out and back, for ever.
  • random: one of these, picked once per visit and kept from page to page; a return visit gets a different one.
  • custom: like random, but only from the ones listed in custom, e.g. custom = ["curve", "cycloid", "ford"].

Licence

GNU GPL v3, or any later version. Use it, change it, run your own site with it; if you share a changed version, share its source under the GPL too.

Your own writing and pictures are yours: set their licence in [license] in config.toml, shown under each post and in the feed. The fonts aren't in this repository; they're downloaded at build time and carry their own licences (both defaults are under the SIL Open Font License).

coppice, a small program that builds a personal site from markdown.
Copyright (C) 2026 The spinney authors

This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.

Documentation

Overview

Fonts from Google Fonts, served from this site.

The build asks Google Fonts for the families named in config.toml, downloads the font files into public/fonts/ and writes public/css/fonts.css to match. Pages only ever load fonts from this site; visitors never contact Google.

Variable fonts come with their full weight range (and optical size, if they have it); static fonts with the few weights the CSS uses. Only the subsets in [fonts] subsets are kept. Everything downloaded is cached in the site's .cache/fonts/, so later builds work offline; delete it to fetch afresh.

Tiny static site generator, run in a site's folder as Jekyll is: its content/ and config.toml into public/, set in coppice's theme (its templates/, styles/ and static/js/, built into the program), with any templates, styles and static files of the site's own over it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL