Latest

DAYS / newest first

Thursday, March 5, 2026

Writing

Stupid sidebar tricks

I wanted to add my name and some external (non-social) links to the main layout. Starlight, being a documentation framework, isn’t really designed with that sort of thing in mind. I decided to use the sidebar, essentially dividing it into a header (for the author’s name), a main area, and a footer (for external links). Note that the sidebar is hidden behind a menu button at mobile sizes.

You can always override Starlight’s <Sidebar> component, which is probably what I should do. But for now, this config-only hack kind of works, helped by some custom CSS for the .author class.

Read full post →

VOD

Bedroom

1,439 min

On YouTube

GitHub commits

Wednesday, March 4, 2026

VOD

On YouTube

GitHub commits

Tuesday, March 3, 2026

Writing

Notes

Sample code for generating OG images with Satori and Resvg:

// src/pages/og/[slug].png.ts
import satori from 'satori';
import { Resvg } from '@resvg/resvg-js';
import { getCollection } from 'astro:content';

export async function getStaticPaths() {
  const posts = await getCollection('blog');
  return posts.map((post) => ({
    params: { slug: post.slug },
    props: { title: post.data.title },
  }));
}

export const GET = async ({ props }) => {
  // Satori requires a font as an ArrayBuffer
  const fontData = await fetch('https://example.com').then(res => res.arrayBuffer());

  const svg = await satori(
    { type: 'div', props: { children: props.title, style: { fontSize: 60 } } },
    { width: 1200, height: 630, fonts: [{ name: 'Inter', data: fontData }] }
  );

  const resvg = new Resvg(svg);
  const pngData = resvg.render().asPng();

  return new Response(pngData, { headers: { 'Content-Type': 'image/png' } });
};

See also astro-og-canvas and astro-opengraph-images. See also the frontmatter of this post for a method of setting the <meta> tags manually.

VOD

On YouTube

Other videos

GitHub commits