Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: ci

on:
pull_request:
branches: [main]
workflow_dispatch:

permissions:
contents: read

jobs:
build:
name: the site builds
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: peaceiris/actions-hugo@v3
with:
hugo-version: "0.167.0"
extended: true
- run: hugo --minify
# A page that builds and says nothing is a page nobody notices is empty.
- name: every repository is on it
run: |
for repo in plot docs brand; do
grep -q "go-plot/$repo" public/index.html \
|| { echo "::error::$repo is not on the page"; exit 1; }
done
echo "the page names every repository this org has"
88 changes: 88 additions & 0 deletions .github/workflows/hugo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Build + deploy the Hugo site to GitHub Pages on every push to main.
# Adapted from the official Hugo template at
# https://gohugo.io/host-and-deploy/host-on-github-pages/.

name: Deploy Hugo site to Pages

on:
push:
branches: [main]
# Build on every pull request too, so a change to the layout, the content or
# the Hugo version has to prove the site still builds before it lands.
# Without this the workflow ran only on main, which meant a dependency bump
# arrived with no signal at all -- its checks read "no checks", which is not
# the same thing as green and must not be merged as if it were.
pull_request:
workflow_dispatch:

# Allow only one concurrent deployment, skipping runs queued between
# the run in-progress and latest queued. Don't cancel in-progress
# runs — we want them to finish before a new build replaces them.
concurrency:
group: "pages"
cancel-in-progress: false

# The build needs nothing beyond the source and the Pages configuration it
# reads to compute the base URL. Publishing rights are granted to the deploy
# job alone, below, so a pull request build cannot replace what is served.
permissions:
contents: read
pages: read

env:
# Pin Hugo so site builds don't break when a new release ships
# incompatible template changes. Bump deliberately, not by
# surprise.
HUGO_VERSION: 0.135.0

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Install Hugo CLI
run: |
wget -O hugo.deb "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/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb"
sudo dpkg -i hugo.deb

- name: Checkout
uses: actions/checkout@v7
with:
submodules: recursive

- name: Setup Pages
id: pages
uses: actions/configure-pages@v6

- name: Build
env:
HUGO_ENVIRONMENT: production
HUGO_ENV: production
run: |
hugo \
--gc \
--minify \
--baseURL "${{ steps.pages.outputs.base_url }}/"

- name: Upload artifact
uses: actions/upload-pages-artifact@v5
with:
path: ./public

deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
permissions:
contents: read
pages: write
id-token: write
# Only main publishes. A pull request stops after build above: it has built
# the site, which is the whole point of the gate, and it has no business
# replacing what is served.
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v5
73 changes: 73 additions & 0 deletions .github/workflows/links.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: links

# The landing had a link to https://github.com/go-fileshare/authnd, which is a
# 404: authnd lives in go-authn. The organisation profile carries the SAME link
# and has it right, because .github/ has a link check and this repository did
# not. A dead link on a landing page breaks nothing that complains.
#
# ⛔ THE CHECK READS THE BUILT SITE, NOT THE LAYOUTS. The first version of this
# file grepped layouts/ and failed on its own first run against
# `https://github.com/go-fileshare/{{ .name }}` -- a Hugo template expression,
# not a URL. Skipping anything with a brace in it would have "fixed" that and
# left the per-repository card links unchecked, which is most of the page's
# links. Building first expands them into the URLs a reader actually gets,
# which is the only set worth checking.

on:
pull_request:
branches: [main]
workflow_dispatch:

permissions:
contents: read

jobs:
links:
name: every link and image resolves
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
submodules: recursive
- uses: peaceiris/actions-hugo@v3
with:
hugo-version: "0.167.0"
extended: true
- run: hugo --minify --destination ./public
- name: Check
run: |
set -uo pipefail
# The character class matters: an extractor that stops only at ) and "
# carries a closing > or < into the request.
urls=$(grep -rhoE 'https?://[^)">< [:space:]]+' public/ | sed 's/[.,]$//' | sort -u)
test -n "$urls" || { echo "::error::no links found; did the site build?"; exit 1; }
echo "checking $(printf '%s\n' "$urls" | wc -l) distinct URLs"
fail=0
while read -r u; do
# img.shields.io renders anything asked of it and proves nothing.
case "$u" in *img.shields.io*) continue ;; esac
# github.com answers curl's blob pages with 503 most of the time
# (7 of 8 on 2026-10-10, all 3 attempts on every run), while the
# raw host answers 200 for a file and 404 for a missing one. A blob
# link claims "this file exists at this ref", so ask the raw host.
# (go-ndarray/docs#30; `landingkit links` does the same, tested.)
probe=$u
case "$u" in
https://github.com/*/*/blob/*)
probe=https://raw.githubusercontent.com/$(printf '%s' "${u#https://github.com/}" | sed -E 's#^([^/]+/[^/]+)/blob/#\1/#; s/[?#].*$//') ;;
esac
# Three attempts: one is a flake detector rather than a link
# checker, and a lane that fails at random is a lane people learn
# to ignore.
code=000
for attempt in 1 2 3; do
code=$(curl -sS -o /dev/null -w '%{http_code}' -L --max-time 25 "$probe" || echo 000)
case "$code" in 2*|3*) break ;; esac
sleep 3
done
case "$code" in
2*|3*) printf ' ok %s %s\n' "$code" "$u" ;;
*) printf ' FAIL %s %s\n' "$code" "$u"; fail=1 ;;
esac
done <<< "$urls"
test "$fail" -eq 0 || { echo "::error::at least one link or image does not resolve"; exit 1; }
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
public/
resources/
.hugo_build.lock
.DS_Store
3 changes: 2 additions & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
BSD 3-Clause License

Copyright (c) 2026, go-plot
Copyright (c) 2026, the go-plot/go-plot.github.io authors
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Expand Down
Empty file added content/_index.md
Empty file.
73 changes: 73 additions & 0 deletions hugo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
baseURL = 'https://go-plot.github.io/'
locale = 'en-us'
title = 'go-plot'
# No theme -- the layout is the go-* family template (go-fileshare.github.io's,
# via logos/landing-kit, as go-fft, go-ndarray and go-notebook use it): one
# self-contained layouts/index.html, partials/styles.html (the shared sheet,
# byte-identical) and partials/theme-toggle.html (system / light / dark).

disableKinds = ['taxonomy', 'term', 'rss', 'sitemap', '404']

[markup.goldmark.renderer]
unsafe = true

[params]
description = "go-plot: pure-Go (CGO=0) plotting for go-ndarray. matplotlib's object model and defaults, figures to SVG and PNG with real TeX labels, tested equal to matplotlib where they can be equal."

# Every field below is rendered by layouts/index.html (cards in #repos, the
# strip under the hero). A field nothing renders does not stay true.
[[params.repos]]
name = "plot"
kind = "library"
href = "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/go-plot/plot"
blurb = "The library: <code>Figure</code>, <code>Axes</code> and every plot type, with <code>ticker</code> (tick locations and labels), <code>colors</code> (the cycle, eight colormaps, norms), <code>contour</code> (marching squares), <code>render</code> (raster and vector SVG back-ends) and <code>text</code> (DejaVu Sans, and TeX through go-tex/math)."
[[params.repos]]
name = "docs"
kind = "site"
href = "https://go-plot.github.io/docs/"
blurb = "The documentation (Hugo + Hextra): getting started, the API and why it has this shape, every plot type with the code that drew it, what is exact against matplotlib, TeX labels, performance, and the differences. <a href=\"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/go-plot/docs\">Source →</a>"
[[params.repos]]
name = "brand"
kind = "assets"
href = "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/go-plot/brand"
blurb = "Logos and icons for the organization, in SVG / PNG / JPG / ICO / ICNS across colour, white and black variants."

# The cards of #exact and their count come from this list. Each statement is
# from go-plot/plot's docs/design.md at v0.1.0.
[[params.checks]]
name = "Ticks, bit for bit"
what = "Tick locations, labels and offset text on 408 axes of real figures (4 sizes, 37 linear and 14 log ranges): every location bit for bit, every label character for character."
[[params.checks]]
name = "Locators and formatters"
what = "45 MaxNLocator, 42 LogLocator, 72 ScalarFormatter and 25 LogFormatterSciNotation cases a default figure never reaches, exact."
[[params.checks]]
name = "Eight colormaps"
what = "viridis, plasma, inferno, magma, cividis, gray, coolwarm, RdBu (and `_r`): 1008 samples per map compared as floats and as bytes."
[[params.checks]]
name = "Named colours and the cycle"
what = "All 148 CSS4 colours, the 10 `tab:` colours, single letters, `C0`–`C9`, grey levels, short and long hex: exact."
[[params.checks]]
name = "Layout, then TightLayout"
what = "15 kinds of figure at two sizes: every Axes position and view limit to 1e-9 relative, every tick label exactly. After `TightLayout` (6 kinds at two sizes), every Axes edge within 0.005 of the figure."
[[params.checks]]
name = "Pixels, side by side"
what = "Twelve reference figures drawn by both put every axes frame and tick mark on the same pixel, and after `TightLayout` within 2 pixels; two deliberately shifted figures must fail, and do."

[params.brand]
# Generated by logos/landing-kit/kit.py from static/img/logo.svg: the colours are
# READ from the logo's gradient, never chosen. Do not add other keys:
# neutrals (backgrounds, surfaces, greys) belong to the shared sheet.
# Contrast: base on white 4.82:1, bright on the dark background 7.94:1.
base = "#1f77b4"
deep = "#13496e"
bright = "#5aaee6"
shadow = "rgba(31,119,180,.7)"
glow = "rgba(31,119,180,.6)"
wash = "rgba(31,119,180,.10)"
washDeep = "rgba(19,73,110,.06)"
chipBg = "#ebf5fc"
chipBorder = "#cee7f8"
chipFg = "#13496e"
chipBgDark = "rgba(90,174,230,.14)"
chipBorderDark = "rgba(90,174,230,.32)"
chipFgDark = "#a4d2f1"
Loading
Loading