Recipes / Theming

Recipes

Theming

Match the grid and skyline to your site, switch with light and dark mode, and change colours with the time of day.

The grid has four colours, and the skyline uses the same theme:

Key Default
base #0c1f33 Resting tile colour.
hover #43d9ad Tiles in a well, a ripple or a data glow. The skyline’s bars use it too.
fog #011627 The colour distant tiles fade into.
fresnel #bfe9ff The rim light on tiles seen at a grazing angle.

The canvas is transparent, so your page shows through between the tiles. Set fog to your page’s background colour. Otherwise the far rows end at a visible edge instead of fading out.

TypeScript
const grid = new SpacetimeGrid(el, { theme: { fog: "#0b1020" } });
grid.setTheme({ hover: "#5ee6ff" });

setTheme takes any subset of the four keys and updates the next frame, including the still frame shown under reduced motion.

Light and dark

These two palettes are the ones abhiramkrishna.com uses. In light mode the tiles go pale and the highlight turns indigo, because the default teal is hard to see on white.

palettes.ts
export const DARK = { base: "#0c1f33", hover: "#43d9ad", fog: "#011627", fresnel: "#bfe9ff" };
export const LIGHT = { base: "#c7d4de", hover: "#4049b0", fog: "#eff4f8", fresnel: "#d7e6f5" };

Follow whatever decides your site’s theme. With a dark class on <html>:

TypeScript
import { SpacetimeGrid } from "@abhiramkrishna/spacetime-grid";
import { DARK, LIGHT } from "./palettes";

const root = document.documentElement;
const palette = () => (root.classList.contains("dark") ? DARK : LIGHT);

const grid = new SpacetimeGrid(el, { theme: palette() });
new MutationObserver(() => grid.setTheme(palette())).observe(root, { attributes: true, attributeFilter: ["class"] });

To follow the operating system instead, listen to matchMedia("(prefers-color-scheme: dark)") and call setTheme in its change event.

Colours that change with the time of day

In dark mode, abhiramkrishna.com moves through four palettes over the day and blends between them. Here they are, if you want the same effect:

day-phases.ts
export const PHASES = {
  night: { base: "#0c1f33", hover: "#43d9ad", fog: "#011627", fresnel: "#bfe9ff" },
  dawn: { base: "#2a1f3d", hover: "#ff9e7a", fog: "#1a1430", fresnel: "#ffd1b8" },
  day: { base: "#123a55", hover: "#5ee6ff", fog: "#04223a", fresnel: "#d8f4ff" },
  dusk: { base: "#2b1b3f", hover: "#c58cff", fog: "#170f2a", fresnel: "#f0c8ff" },
};

export function phaseAt(hour: number): keyof typeof PHASES {
  if (hour < 5.5 || hour >= 19.75) return "night";
  if (hour < 7.75) return "dawn";
  if (hour < 17.25) return "day";
  return "dusk";
}
TypeScript
const update = () => {
  const now = new Date();
  grid.setTheme(PHASES[phaseAt(now.getHours() + now.getMinutes() / 60)]);
};
update();
setInterval(update, 60_000);

Set your page background to the phase’s fog colour at the same time, so the fade still lines up.

The skyline

  • As a layer on a grid, the bars use the grid’s hover colour and change with it. Set the skyline’s color option to give them their own colour.
  • Standalone, ContributionSkyline takes the same theme option and has its own setTheme().
  • The 2D calendar is plain HTML, so it’s themed with CSS variables. To match the light palette above:
CSS
.calendar {
  --cs-accent: #4049b0;
  --cs-empty: #c7d4de;
  --cs-text: #52697d;
  --cs-strong: #011627;
}