Skip to content

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:

![Board pinout](pinouts/board/board.pinout.html){ type=iframe }

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
![Mount the fan](3d/fan/fan.3dstep.html){ type=iframe }

Ignore the generated files so they never get committed by accident:

docs/pinouts/**/*.pinout.html
docs/3d/**/*.3dstep.html

Enable md-iframe

In mkdocs.yml, beside attr_list:

markdown_extensions:
  - attr_list
  - md_iframe

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.