Skip to content

dvhthomas/blog

Repository files navigation

My Blog

Bits By Me uses the blog uses the hugo static site generator. Publishing articles is easy; working with Jupyter notebooks that become embedded GitHub gists is slightly more involved.

Prerequisites

The easiest way to start is to use a GitHub Codespace or run locally as a devcontainer in VS Code (see devcontainer.json for details).

If you must use locally then you need to install:

Required:

  • Go - I use asdf so asdf install golang latest works for me.
  • Hugo - brew install hugo
  • Task - go install github.com/go-task/task/v3/cmd/task@latest && asdf reshim.
  • D2 - curl -fsSL https://d2lang.com/install.sh | sh -s -- (required if using D2 diagrams)
  • Chrome or Chromium - Required for resume PDF generation. Usually already installed on macOS/Linux. On Ubuntu: sudo apt-get install chromium-browser

Author and publish

Write a new blog post by providing a TITLE and calling the task blog:

TITLE="some-factoid" task blog
...write write write...
git add .
git commit -m "my cool post"
git push origin master

Today I Learned posts work exactly the same way - provide a TITLE:

TITLE="something-i-learned" task til
# OR
TITLE="something-i-learned" task today-i-learned

Each post is put into a folder like blog/1971/01/01/my-post-title/index.md or til/1971/01/01/my-til-title/index.md. This gives you a spot to drop post-specific content next to the post itself. For example, if you want an image for a post you can drop it in that folder and reference it in the post thus:

Recipes work similarly - provide a TITLE:

TITLE="chocolate-chip-cookies" task recipe

Recipe pages include:

  • Kitchen-optimized layout (large text, mobile-friendly)
  • Schema.org Recipe structured data for SEO
  • Unit conversion reference at /recipes/units/
  • Print-friendly layout
  • Color-coded taxonomy tags (cuisines, categories, diets)

Recipe markdown uses nested shortcodes to extract ingredients and instructions for schema.org:

{{< recipe >}}

### Ingredients
{{< ingredients >}}
- 2 cups flour
- 1 cup sugar
{{< /ingredients >}}

### Instructions
{{< instructions >}}
**Prep:** Mix dry ingredients...
**Bake:** Pour into pan and bake at 350°F...
{{< /instructions >}}

{{< /recipe >}}

Hosting

The blog itself is hosting on GitHub Pages. The DNS configuration is in Squarespace Domains accessible using my personal Google account.

Development Workflow

Start the dev server (recommended):

task                      # Renders D2 diagrams + starts Hugo dev server
# OR
go run blog.go --serve    # Same thing without Task

Visit http://localhost:1313 to preview. The server watches for changes and automatically:

  • Re-renders D2 diagrams when .d2 files change
  • Rebuilds Hugo when markdown/templates change
  • Reloads your browser

Build for production:

task build                           # Renders D2 + builds Hugo + generates resume PDF
# OR manually:
go run blog.go && hugo --gc --minify && go run blog.go  # D2 → Hugo → PDF

The build process:

  1. Renders D2 diagrams to SVG
  2. Builds Hugo site to public/
  3. Generates public/resume.pdf from public/resume/index.html

Look at the draft Tips post to see examples of how you can use various elements like diagrams, code, and tweets.

Content pre-processing

D2 Diagrams

The blog supports D2 diagrams - a modern declarative diagram language. D2 files in your page bundles are automatically rendered to SVG images during the build process.

Prerequisites

Install D2:

# Install D2 (required for rendering diagrams)
curl -fsSL https://d2lang.com/install.sh | sh -s --
# Or via Go:
go install oss.terrastruct.com/d2@latest

Using D2 diagrams in posts

  1. Create a D2 file in your page bundle directory:
# Example: content/blog/2025-10-17/my-post/diagram.d2
x -> y -> z: Simple flow
a -> b: {
  style.stroke: "#0d32b2"
  style.fill: "#c2d2e0"
}
  1. Reference it in your post using the d2 shortcode:
{{</* d2 src="diagram.d2" */>}}
  1. Optional: Add a caption:
{{</* d2 src="diagram.d2" */>}}
This diagram shows the data flow through our system.
{{</* /d2 */>}}

Site-wide configuration

You can set D2 rendering options for all diagrams in config.toml:

[params.d2]
    theme = "6"         # D2 theme: number (0-8) or name like "cool-classics"
    layout = "elk"      # Layout engine: "dagre", "elk", etc.
    sketch = true       # Enable hand-drawn style globally

Available themes: Run d2 --list-themes to see all available themes. Available layouts: Run d2 --list-layouts to see all available layout engines.

Note: These settings apply to all D2 diagrams site-wide. They're used during the render step before Hugo builds the site.

Shortcode usage

The shortcode is simple - just reference your D2 file:

{{</* d2 src="diagram.d2" */>}}

With a caption:

{{</* d2 src="diagram.d2" */>}}
This diagram shows the system architecture.
{{</* /d2 */>}}

The only parameter is:

  • src (required): Path to the .d2 file relative to your page bundle

How it works

Development mode (task):

  • Renders all D2 files once at startup
  • Starts Hugo dev server with the blog.go tool
  • Watches for changes to .d2 files and automatically re-renders them
  • Hugo detects the SVG changes and reloads the page

Build mode (task build):

  • Renders all D2 files before building
  • Generates static site in public/ directory

Generated files:

  • SVG files generated from .d2 files are not tracked in git (see .gitignore)
  • Only commit your .d2 source files
  • Generated SVGs are recreated during dev/build

Manual rendering

# Render all D2 diagrams
task render-d2

# Or use the Go tool directly
go run blog.go

# Watch D2 files only (no Hugo server)
go run blog.go --watch

# Verbose output
go run blog.go --verbose

Troubleshooting

Diagrams not appearing:

  • Ensure D2 is installed: d2 --version
  • Check that the .svg file was generated next to your .d2 file
  • Verify the src path in your shortcode matches the actual file name
  • Try manually running: task render-d2

Compress PNG Images

Following this advice it's a good idea to compress PNG images before adding to Git. Typical results: 480KB → 70KB (85% reduction).

Prerequisites

Install the compression tools once:

# macOS
brew install pngquant oxipng

# Linux (Ubuntu/Debian)
sudo apt install pngquant
cargo install oxipng

Using the squish script

The squish script recursively finds and compresses all PNG images in a directory:

# Preview what will be compressed (dry-run, safe)
./squish content/blog/2021/05/11

# Actually compress images (creates -fs8.png versions)
./squish content/blog/2021/05/11 --now

# Replace original images with compressed versions (destructive!)
./squish content/blog/2021/05/11 --now --clean

Features:

  • Recursively finds all PNG files in a directory
  • Handles filenames with spaces
  • Shows before/after sizes and compression ratios
  • Safe by default (dry-run mode)
  • Intermediate -fs8.png files are git-ignored

Workflow:

  1. Add images to your post directory
  2. Run ./squish <path> to preview
  3. Run ./squish <path> --now to compress
  4. Review the -fs8.png files
  5. Run ./squish <path> --now --clean to replace originals
  6. Commit the compressed images

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 5