Vitrine
A Hugo theme for documentation, with examples that run on the page next to their code.
- Hugo 0.146 or newer
- No JavaScript framework
- llms.txt
- MIT licence
hugo mod get github.com/maxfettinger/vitrineA live example
The walk below runs on this page. Under it are the files it’s made of, exactly as they run: no build step, and no second copy of the code to keep in sync.
<canvas id="walk" width="720" height="240" aria-label="A random walk on a grid"></canvas>
<button id="walk-again" type="button">Another walk</button>/* Only this example's canvas: the theme wraps this file in @scope */
canvas {
display: block;
width: 100%;
height: auto;
margin-bottom: 0.75rem;
border-radius: 0.4rem;
background: var(--bg-soft);
}// A random walk: one step up, down, left or right at a time, in the theme's accent colour. With reduced motion the
// whole walk appears at once.
const canvas = document.getElementById("walk");
const context = canvas.getContext("2d");
const step = 8;
const moves = [[step, 0], [-step, 0], [0, step], [0, -step]];
const still = matchMedia("(prefers-reduced-motion: reduce)").matches;
let frame;
function walk() {
cancelAnimationFrame(frame);
const { width, height } = canvas;
context.clearRect(0, 0, width, height);
context.strokeStyle = getComputedStyle(canvas).getPropertyValue("--accent");
context.lineWidth = 2;
context.lineCap = "round";
let x = width / 2;
let y = height / 2;
let steps = 0;
const draw = () => {
for (let i = 0; i < (still ? 800 : 4); i++, steps++) {
const [dx, dy] = moves[Math.floor(Math.random() * moves.length)];
const nx = Math.min(Math.max(x + dx, step), width - step);
const ny = Math.min(Math.max(y + dy, step), height - step);
context.beginPath();
context.moveTo(x, y);
context.lineTo(nx, ny);
context.stroke();
[x, y] = [nx, ny];
}
if (steps < 800) frame = requestAnimationFrame(draw);
};
draw();
}
document.getElementById("walk-again").addEventListener("click", walk);
walk();What you get
Examples that run. A folder with example.html, and optionally style.css and script.js, becomes a live demo
with its files in tabs below it. Its CSS is scoped to the example, its script runs as a module, and an import map
lets the script import a library by its npm name. See Live examples.
Navigation. Tabs across the top for the site’s sections, a two-level sidebar for the section you’re in, “On this page” on the right, previous and next at the bottom. See Pages and navigation.
Docs for AI assistants. llms.txt, llms-full.txt and a Markdown copy of every page, with no setup. See
llms.txt.
Small. Plain CSS and one small script, no framework and no Node build. Hugo does everything.