Skip to main content

Contributing Software Tool Documentation

This guide covers two things: setting up the repo locally and opening a pull request, and embedding a software tool repository as a Git submodule with optional auto-generated API docs.


Local development workflow

Prerequisites

  • Node.js 20 or later — nodejs.org
  • Git with submodule support

1. Clone and initialise

git clone https://github.com/robotiq/robotiq.github.io
cd robotiq.github.io
git submodule update --init

2. Install dependencies

npm install

3. Sync external docs

The sync script pulls content from submodules into docs/. It runs automatically on npm start and npm run build, but you can trigger it manually at any time to verify a new sync job:

node scripts/sync-external-docs.js

4. Start the dev server

npm start

Opens http://localhost:3000 in your browser. The page hot-reloads when you edit files under docs/, src/, or sidebars.js.

5. Open a pull request

  1. Create a branch:
    git checkout -b my-feature
  2. Commit your changes:
    git add .
    git commit -m "Add FT300 Python tool page"
  3. Push and open a pull request from your branch to main:
    git push -u origin my-feature

The CI pipeline builds the site and reports broken links or MDX errors before the PR is merged.


How it works

Each software tool (SDK, driver, ROS package, …) lives in its own GitHub repository. Embedding it here works in two steps:

  1. Submodule — a Git submodule under external/ acts as a pinned import of the tool's repository. It does not copy files; it records the exact commit of the source repo that this site should use. Running git submodule update --init checks out those commits locally so their files become available.

  2. Sync scriptscripts/sync-external-docs.js reads the checked-out submodule files and copies the ones you declare into docs/, rewriting relative links so they resolve correctly on this site.

Repository layout

robotiq.github.io/
├── external/ ← pinned imports of source repos
│ └── tactile_sensors/ ← TSF-85 SDK repo
├── docs/
│ ├── intro.mdx ← overview page, includes the
│ │ auto-generated software tools tables
│ └── drivers/
│ ├── TSF-85/
│ │ ├── index.mdx ← product landing page (in git)
│ │ ├── SDK/
│ │ │ ├── C++/
│ │ │ │ ├── index.mdx ← wrapper page (in git)
│ │ │ │ └── _readme.md ← synced from submodule
│ │ │ └── Python/
│ │ │ ├── index.mdx
│ │ │ └── _readme.md
│ │ ├── ROS/
│ │ │ └── ROS2/index.mdx
│ │ └── Physics Engine/
│ │ └── Isaac Sim/index.mdx
│ ├── FT300/
│ │ ├── index.mdx
│ │ ├── SDK/C/ …
│ │ ├── SDK/Python/ …
│ │ └── ROS/ROS2/ …
│ └── 2F hande/
│ ├── index.mdx
│ ├── SDK/C++/ …
│ ├── SDK/Python/ …
│ ├── ROS/ROS2/ …
│ ├── Physics Engine/Isaac Sim/ …
│ ├── Physics Engine/PyBullet/ …
│ └── GraspGen/ … ← "Other" category, no wrapper folder needed
├── draft/ ← content with no nav link yet (never
│ built into a page — outside docs/)
├── scripts/
│ ├── sync-external-docs.js
│ └── generate-tools-table.js
└── sidebars.js

Files prefixed with _ are Docusaurus partials — imported by a wrapper .mdx but not standalone pages themselves.

The SDK/, ROS/, and Physics Engine/ folders are just organizational containers — generate-tools-table.js doesn't care about folder names, only about which index.mdx files carry a Category badge (see step 3 below). GraspGen/ proves the point: it sits directly under the product folder with no wrapper category folder, and still lands in the "Other" table because of its badge, not its path.

Excluding content from a synced README

A tool repo's README often carries things that only make sense on GitHub — e.g. a "full documentation at robotiq.github.io/..." blurb, which would be redundant (or circular) once that same README is copied onto this site. Wrap that content in a pair of HTML comment markers:

<!-- docs-site:exclude -->
📖 Full documentation: https://robotiq.github.io/...
<!-- /docs-site:exclude -->

GitHub renders the text between the markers normally on the tool repo's own README (HTML comments are invisible), but sync-external-docs.js strips everything between <!-- docs-site:exclude --> and <!-- /docs-site:exclude --> before copying content into docs/, so it never reaches this site.


Step-by-step: adding a new software tool

The steps below add a Python tool for the 2F hande gripper family hosted at https://github.com/robotiq/2f85-python-driver.

1. Add the submodule

This registers the tool's repository as a pinned import under external/. Every contributor who clones this site will get the same version of the source repo.

git submodule add \
https://github.com/robotiq/2f85-python-driver \
external/2f85_python
git submodule update --init

2. Declare the sync job

Open scripts/sync-external-docs.js and add an entry to the JOBS array. Each job copies one file or folder from the submodule into docs/:

{
submodule: '2f85_python',
repoUrl: 'https://github.com/robotiq/2f85-python-driver',
branch: 'main',
from: 'README.md',
to: 'drivers/2F hande/SDK/Python/_readme.md',
},

For a repo that contains multiple tools, add one job per tool:

// C++ tool
{
submodule: '2f85_drivers',
repoUrl: '...',
branch: 'main',
from: 'sdk_cpp/README.md',
to: 'drivers/2F hande/SDK/C++/_readme.md',
},

// Python tool
{
submodule: '2f85_drivers',
repoUrl: '...',
branch: 'main',
from: 'python/README.md',
to: 'drivers/2F hande/SDK/Python/_readme.md',
},

Test locally:

node scripts/sync-external-docs.js

3. Create the wrapper page

Create docs/drivers/2F hande/SDK/Python/index.mdx. This file is tracked in git and controls the page title, sidebar label, and any introductory text above the synced README:

---
title: Python
sidebar_label: Python
sidebar_position: 2
---

![SDK](https://img.shields.io/badge/Category-SDK-lightgrey)

![Supported by Robotiq](https://img.shields.io/badge/Supported_by-Robotiq-blue)

Brief description and link to the source repository.

## Intro

import Readme from './_readme.md';

<Readme />

The ## Intro heading and the import are optional — omit them if there is no synced README or if the content should start directly.

Both badges are required, not decorativegenerate-tools-table.js walks the folder tree looking for the Category badge to decide which table a page belongs to, and reads the Supported_by badge for the cell shown in that table (see Auto-generated software tools tables below). Valid Category values: SDK, Physics_Engine, Other, ROS1, ROS2 (ROS pages use a different badge block — see below). Use Supported_by-Robotiq-blue for tools developed and maintained by Robotiq, or Supported_by-Third_party-lightgrey for community-maintained tools.

ROS pages are different. Instead of one Supported_by badge, a ROS tool page carries one Distro badge per supported ROS distribution, each immediately followed by its own Supported_by badge — that's what drives the ROS1/ROS2 distro-compatibility tables:

---
title: ROS
sidebar_label: ROS
sidebar_position: 3
---

![Category](https://img.shields.io/badge/Category-ROS2-lightgrey)<br />
![Distro](https://img.shields.io/badge/Distro-Jazzy-lightgrey)
![Supported by Robotiq](https://img.shields.io/badge/Supported_by-Robotiq-blue)

For a tool supporting several distros, repeat the Distro/Supported_by pair for each one (see docs/drivers/2F hande/ROS/ROS2/index.mdx for a three-distro example). Use Category-ROS1 instead of Category-ROS2 for a ROS 1 package.

No README or no software tool yet? Skip steps 1 and 2 entirely and write the index.mdx manually. This is the right approach when a tool is planned but not yet available, or when the source repo has no suitable README to pull in. Write the page content directly with no import:

---
title: Python
sidebar_label: Python
sidebar_position: 2
---

![SDK](https://img.shields.io/badge/Category-SDK-lightgrey)

![Supported by Robotiq](https://img.shields.io/badge/Supported_by-Third_party-lightgrey)

Coming soon. In the meantime, see
[org/repo](https://github.com/robotiq/...) on GitHub.

The page still appears in the sidebar and can be updated to import a synced README later, once the tool or its documentation exists.

4. Create the product landing page

If the product folder has no index.mdx yet, create docs/drivers/2F hande/index.mdx:

---
title: 2F / Hand-E
sidebar_label: 2F / Hand-E
sidebar_position: 0
---

Short description of the product family.

## Available drivers

### SDK

{/* AUTO-GENERATED-PRODUCT-SDK-TABLE:START */}
{/* AUTO-GENERATED-PRODUCT-SDK-TABLE:END */}

### ROS

#### ROS2

{/* AUTO-GENERATED-PRODUCT-ROS2-TABLE:START */}
{/* AUTO-GENERATED-PRODUCT-ROS2-TABLE:END */}

#### ROS1

{/* AUTO-GENERATED-PRODUCT-ROS1-TABLE:START */}
{/* AUTO-GENERATED-PRODUCT-ROS1-TABLE:END */}

### Physics Engine

{/* AUTO-GENERATED-PRODUCT-PHYSICS_ENGINE-TABLE:START */}
{/* AUTO-GENERATED-PRODUCT-PHYSICS_ENGINE-TABLE:END */}

### Other

{/* AUTO-GENERATED-PRODUCT-OTHER-TABLE:START */}
{/* AUTO-GENERATED-PRODUCT-OTHER-TABLE:END */}

Don't write any of the five tables by hand — leave each marker pair next to each other and scripts/generate-tools-table.js fills in a single-row version of the matching category table (see below) on the next build. The title here is what shows up as the row label there. A category with no tool yet renders a short "not documented yet" placeholder instead of an empty table, so it's safe to keep all five headings even before every category has content.

5. Register in sidebars.js

Add a category entry with a link pointing at the product landing page, nesting the tool pages under an SDK / ROS / Physics Engine / Other sub-category matching where they live on disk:

{
type: 'category',
label: '2F / Hand-E',
link: { type: 'doc', id: 'drivers/2F hande/index' },
items: [
{
type: 'category',
label: 'SDK',
items: [
'drivers/2F hande/SDK/C++/index',
'drivers/2F hande/SDK/Python/index',
],
},
{
type: 'category',
label: 'ROS',
items: [
'drivers/2F hande/ROS/ROS2/index',
],
},
{
type: 'category',
label: 'Physics Engine',
items: [
'drivers/2F hande/Physics Engine/Isaac Sim/index',
'drivers/2F hande/Physics Engine/PyBullet/index',
],
},
{
type: 'category',
label: 'Other',
items: [
'drivers/2F hande/GraspGen/index',
],
},
],
},

Only include the sub-categories that actually have pages — e.g. FT300-S has no Physics Engine or Other tools yet, so its sidebar entry skips those two groups entirely.


Auto-generated software tools tables

docs/intro.mdx has five "Software tools" tables, one per category — SDK, ROS2, ROS1, Physics Engine, Other — each listing every product that has a tool in that category, with each cell showing that tool's support badge linked to its page. Each product's own landing page (docs/drivers/<Product>/index.mdx) gets the same five tables, single-row versions scoped to just that product. You never edit any of them by hand — all ten (five global + five per-product) are regenerated by scripts/generate-tools-table.js, which runs automatically on npm start / npm run build (same as sync-external-docs.js).

The script walks each docs/drivers/<Product>/ folder tree looking for tool leaf pages — an index.mdx carrying a Category badge — regardless of how deeply it's nested (SDK/, ROS/, Physics Engine/, or no container folder at all, as with GraspGen/). For each leaf page found:

  • Row — the product's own title frontmatter (from docs/drivers/<Product>/index.mdx).
  • SDK / Physics Engine / Other pages — column = the tool's title frontmatter; cell = its Supported_by-<Label>-<color> badge (see step 3 above), shown compactly (no "Supported by" prefix — only the source page keeps the full badge).
  • ROS1 / ROS2 pages — columns = the distros named in that page's Distro-<Name> badges; cell = the Supported_by badge immediately following each one.

This means adding a new product or tool page, with a title and the right badges, is enough to make it appear in the matching tables on the next build — no manual edit needed. A category with no products yet renders a short placeholder line instead of an empty table.

A few things are still hand-maintained in the script itself, by design — they're presentation choices, not derivable from the file tree:

  • COLUMN_ORDER / DISTRO_ORDER — preferred left-to-right order for each category's columns / each ROS table's distro columns. Anything not listed still gets its own column, just sorted alphabetically after the known ones.
  • COLUMN_DESCRIPTIONS / DISTRO_DESCRIPTIONS — the one-line legend shown under each table. A column or distro without an entry here still appears, just with no legend line, until one is added.

To test a change locally:

node scripts/generate-tools-table.js

It rewrites the content between each AUTO-GENERATED-<CATEGORY>-TABLE marker pair (AUTO-GENERATED-SDK-TABLE, AUTO-GENERATED-ROS2-TABLE, AUTO-GENERATED-ROS1-TABLE, AUTO-GENERATED-PHYSICS_ENGINE-TABLE, AUTO-GENERATED-OTHER-TABLE) in docs/intro.mdx, and the matching AUTO-GENERATED-PRODUCT-<CATEGORY>-TABLE marker pairs in each product's own index.mdx — leaving the rest of each page untouched. The two sets of markers use different link styles on purpose: docs/intro.mdx needs root-relative links (drivers/<Product>/<Tool>), while a product page needs page-relative links (<Tool>), since it already lives inside docs/drivers/<Product>/. Reusing the root-relative form on a product page silently doubles the path (e.g. drivers/2F hande/drivers/2F hande/C++) — the script keeps these as two separate href fields (href vs localHref) to avoid that.


Auto-generated API reference from docstrings

Software tool repos can expose a machine-generated API reference page — no manual writing required. The sync script runs the generation tool against the submodule during build.

Python — pydoc-markdown

In the tool repository, add docstrings following Google or NumPy style, and commit a pydoc-markdown.yml config at the repo root:

# pydoc-markdown.yml (in the tool repo)
loaders:
- type: python
search_path: [.]
packages: [your_package_name]
renderer:
type: markdown
filename: docs/api.md
render_toc: true

In this site, install the tool once:

npm install --save-dev pydoc-markdown

Then add a generation step to scripts/sync-external-docs.js before the JOBS loop:

const { execSync } = require('child_process');

execSync('pydoc-markdown', {
cwd: path.join(ROOT, 'external', '2f85_python'),
stdio: 'inherit',
});

This writes external/2f85_python/docs/api.md. Copy it with a normal job:

{
submodule: '2f85_python',
repoUrl: 'https://github.com/robotiq/2f85-python-driver',
branch: 'main',
from: 'docs/api.md',
to: 'drivers/2F hande/SDK/Python/api.md',
},

Add 'drivers/2F hande/SDK/Python/api' to the sidebar items.

C++ — Doxygen + Doxybook2

In the tool repository, add Doxygen-style comments to headers and commit a Doxyfile configured to output XML:

# Doxyfile (relevant lines)
GENERATE_XML = YES
XML_OUTPUT = doxygen-xml
GENERATE_HTML = NO
INPUT = .
RECURSIVE = YES

In this site, install the tools once:

# Doxygen: https://www.doxygen.nl/download.html (add to PATH)
npm install --save-dev @mikaelkristiansson87/doxybook2

Add generation steps to scripts/sync-external-docs.js:

const submoduleDir = path.join(ROOT, 'external', '2f85_cpp');
const xmlOut = path.join(submoduleDir, 'doxygen-xml');
const mdOut = path.join(submoduleDir, 'docs/api');

execSync('doxygen', { cwd: submoduleDir, stdio: 'inherit' });

execSync(
`doxybook2 --input ${xmlOut} --output ${mdOut}` +
` --config .doxybook/config.json`,
{ cwd: submoduleDir, stdio: 'inherit' }
);

Then copy the output with a folder job:

{
submodule: '2f85_cpp',
repoUrl: 'https://github.com/robotiq/2f85-cpp-driver',
branch: 'main',
from: 'docs/api',
to: 'drivers/2F hande/SDK/C++/api',
},

Add 'drivers/2F hande/SDK/C++/api' (or its sub-pages) to the sidebar.


Quick reference

WhatWhere
Submodules (pinned repo imports)external/<submodule>/
Sync + generation configscripts/sync-external-docs.jsJOBS
Exclude README content from the synced page<!-- docs-site:exclude --> ... <!-- /docs-site:exclude --> in the tool repo's README
Synced partialsdocs/drivers/<Product>/<Category>/<Tool>/_readme.md
Wrapper pagesdocs/drivers/<Product>/<Category>/<Tool>/index.mdx
Category badge (SDK / ROS1 / ROS2 / Physics_Engine / Other)![...](.../Category-<Name>-lightgrey) at the top of each wrapper page
Support badge (non-ROS tables)![Supported by <Label>](.../Supported_by-<Label>-<color>), right after the Category badge
Distro + support badges (ROS tables)one Distro-<Name> badge per supported distro, each immediately followed by its own Supported_by-<Label>-<color> badge
Product landing pagesdocs/drivers/<Product>/index.mdx
Generated API pagesdocs/drivers/<Product>/<Category>/<Tool>/api.md
Draft / not-yet-linked content (never built into a page)draft/ at the repo root, outside docs/
Auto-generated tools tables scriptscripts/generate-tools-table.js
Auto-generated overview tables outputdocs/intro.mdx, between each AUTO-GENERATED-<CATEGORY>-TABLE marker pair
Auto-generated per-product tables outputdocs/drivers/<Product>/index.mdx, between each AUTO-GENERATED-PRODUCT-<CATEGORY>-TABLE marker pair
Sidebar configsidebars.js
Doc ID formatdrivers/TSF-85/SDK/C++/index