Publish on a docs site
The tools on this site produce HTML pages, and md-iframe embeds them in an MkDocs or Zensical site. Rather than committing generated pages, it is usually better to generate them during the build: keep only the sources in the repository, and let CI produce the HTML on every deploy. This site is built exactly this way.
The example below uses PinConnect, 3DStep and GitHub Pages; the pattern is the same for any tool and any host.
Lay out the sources
Keep one folder per board, holding its TOML and its image. CI writes <board>.pinout.html beside each TOML, exactly where the embed tag on your page points:
docs/
├── boards.md
└── pinouts/
└── board/
├── board.toml ← committed
├── board.png ← committed
└── board.pinout.html ← generated by CI, not committed
The page embeds the generated file:
3DStep pages work the same way, with one folder per page holding its project and the GLB files of its models. CI writes <name>.3dstep.html beside each project:
docs/
├── assembly.md
└── 3d/
└── fan/
├── fan.toml ← committed
├── board.glb ← committed
├── fan.glb ← committed
└── fan.3dstep.html ← generated by CI, not committed
Ignore the generated files so they never get committed by accident:
Enable md-iframe
In mkdocs.yml, beside attr_list:
Generate in the workflow
Add these steps to your workflow before mkdocs gh-deploy or zensical build:
- run: pip install "git+https://github.com/xbst/PinConnect.git@master"
- run: pip install "git+https://github.com/xbst/md-iframe.git@master"
- name: Generate interactive pinouts
run: |
shopt -s nullglob
for toml in docs/pinouts/*/*.toml; do
echo "pinconnect $toml"
pinconnect "$toml" -i
done
-i embeds the board image into the HTML, so the built site does not depend on the image path resolving. shopt -s nullglob keeps the loop quiet when a folder has no TOML yet.
For 3DStep pages, add:
- run: pip install "git+https://github.com/xbst/3DStep.git@master"
- name: Generate 3D assembly instructions
run: |
shopt -s nullglob
for toml in docs/3d/*/*.toml; do
echo "3dstep $toml"
3dstep "$toml"
done
A 3DStep page always carries its models inside it, so the loop needs no flag. A repository that keeps only the STEP files can convert them in the same job, before the loop, with the step extra; see Convert a STEP file for why committing the GLB files the designer wrote is usually the better choice.
Install from master rather than pinning a release
Each deploy then regenerates your pages with the current version of the tools, so fixes and new features in the generated page, such as tooltip behavior, theming, accessibility and the mobile layout, reach your published site automatically.
A complete workflow
This is a whole GitHub Pages workflow for a Zensical site, the one this site uses. Save it as .github/workflows/ci.yml, and set the repository's Pages source to GitHub Actions:
name: ci
on:
push:
branches:
- master
- main
permissions:
contents: read
pages: write
id-token: write
jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- uses: actions/configure-pages@v6
- uses: actions/checkout@v7
- uses: actions/setup-python@v6
with:
python-version: 3.x
- run: pip install zensical
- run: pip install "git+https://github.com/xbst/PinConnect.git@master"
- run: pip install "git+https://github.com/xbst/3DStep.git@master"
- run: pip install "git+https://github.com/xbst/md-iframe.git@master"
- name: Generate interactive pinouts
run: |
shopt -s nullglob
for toml in docs/pinouts/*/*.toml; do
echo "pinconnect $toml"
pinconnect "$toml" -i
done
- name: Generate 3D assembly instructions
run: |
shopt -s nullglob
for toml in docs/3d/*/*.toml; do
echo "3dstep $toml"
3dstep "$toml"
done
- run: zensical build --clean
- uses: actions/upload-pages-artifact@v5
with:
path: site
- uses: actions/deploy-pages@v5
id: deployment
Leave out the steps of a tool you do not use. For MkDocs, install mkdocs-material instead of zensical, and run mkdocs build in place of zensical build --clean.
Build locally
Run the same steps on your machine to preview the site. In a virtual environment with the same packages installed:
PowerShell
Get-ChildItem docs/pinouts/*/*.toml | ForEach-Object { pinconnect $_.FullName -i }
Get-ChildItem docs/3d/*/*.toml | ForEach-Object { 3dstep $_.FullName }
zensical serve
Linux / macOS
for toml in docs/pinouts/*/*.toml; do pinconnect "$toml" -i; done
for toml in docs/3d/*/*.toml; do 3dstep "$toml"; done
zensical serve
Rerun the loops after editing a TOML: the dev server rebuilds the page, but not the pinout or the 3D page.
A shared theme
A site-wide theme, matching your site's colors and fonts, can live once beside the folders, one for each tool. Each board points at it with theme_dir:
[board]
title = "My board"
image = "board.png"
width = 1920
height = 1080
theme = "mysite"
theme_dir = ".."
with the theme in docs/pinouts/mysite.toml. The loop above only renders docs/pinouts/*/*.toml, so the theme itself is never rendered as a board. This site's OwlFC-Mini example uses one; see PinConnect themes reference.
3DStep projects do the same with a 3DStep theme in docs/3d/mysite.toml:
[assembly]
title = "Mount the fan"
models = ["board.glb", "fan.glb"]
theme = "mysite"
theme_dir = ".."
The two tools' theme files have the same shape but their own tokens, so a site keeps one for each. This site's PiCAN 2 example uses one; see 3DStep themes reference. The 3DStep designer cannot read the folder, so open the site theme's .toml together with a project to work on it there; its Generate then gives the page the loop renders.