Skip to content
Open
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
5 changes: 5 additions & 0 deletions .github/workflows/license-exceptions.json
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,11 @@
"package": "certifi",
"license": "Mozilla Public License 2.0 (MPL 2.0)"
},
{
"package": "nvidia-sphinx-theme",
"license": null,
"comment": "BSD"
},
{
"package": "rl_games",
"license": "UNKNOWN",
Expand Down
5 changes: 5 additions & 0 deletions docs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ BUILDDIR = _build

.PHONY: multi-docs
multi-docs:
@echo "Generating version switcher..."
@python3 generate_switcher.py
@echo "Building multi-version documentation..."
@sphinx-multiversion "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS)
@echo "Copying redirect page..."
@cp _redirect/index.html $(BUILDDIR)/index.html
@echo "Documentation built successfully!"

.PHONY: current-docs
current-docs:
Expand Down
6 changes: 4 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Building Documentation

We use [Sphinx](https://www.sphinx-doc.org/en/master/) with the [Book Theme](https://sphinx-book-theme.readthedocs.io/en/stable/) for maintaining and generating our documentation.
We use [Sphinx](https://www.sphinx-doc.org/en/master/) with NVIDIA's modified version of the [PyData Sphinx Theme](https://pydata-sphinx-theme.readthedocs.io/en/stable/) for maintaining and generating our documentation.

> **Note:** To avoid dependency conflicts, we strongly recommend using a Python virtual environment to isolate the required dependencies from your system's global Python environment.

Expand All @@ -22,6 +22,7 @@ make current-docs
# 3. Open the current docs
xdg-open _build/current/index.html
```

</details>

<details> <summary><strong>Windows</strong></summary>
Expand All @@ -37,8 +38,8 @@ make current-docs
:: 3. Open the current docs
start _build\current\index.html
```
</details>

</details>

## Multi-Version Documentation

Expand Down Expand Up @@ -72,4 +73,5 @@ make multi-docs
:: 3. Open the multi-version docs
start _build\index.html
```

</details>
21 changes: 0 additions & 21 deletions docs/_templates/versioning.html

This file was deleted.

75 changes: 38 additions & 37 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@
#
import os
import sys
from datetime import datetime

sys.path.insert(0, os.path.abspath("../source/isaaclab"))
sys.path.insert(0, os.path.abspath("../source/isaaclab/isaaclab"))
sys.path.insert(0, os.path.abspath("../source/isaaclab_contrib"))
sys.path.insert(0, os.path.abspath("../source/isaaclab_contrib/isaaclab_contrib"))
sys.path.insert(0, os.path.abspath("../source/isaaclab_assets"))
sys.path.insert(0, os.path.abspath("../source/isaaclab_assets/isaaclab_assets"))
sys.path.insert(0, os.path.abspath("../source/isaaclab_tasks"))
Expand All @@ -28,13 +31,11 @@
sys.path.insert(0, os.path.abspath("../source/isaaclab_rl/isaaclab_rl"))
sys.path.insert(0, os.path.abspath("../source/isaaclab_mimic"))
sys.path.insert(0, os.path.abspath("../source/isaaclab_mimic/isaaclab_mimic"))
sys.path.insert(0, os.path.abspath("../source/isaaclab_contrib"))
sys.path.insert(0, os.path.abspath("../source/isaaclab_contrib/isaaclab_contrib"))

# -- Project information -----------------------------------------------------

project = "Isaac Lab"
copyright = "2022-2025, The Isaac Lab Project Developers."
copyright = f"2022-{datetime.now().year}, The Isaac Lab Project Developers."
author = "The Isaac Lab Project Developers."

# Read version from the package
Expand Down Expand Up @@ -227,11 +228,8 @@

# -- Options for HTML output -------------------------------------------------

import sphinx_book_theme

html_title = "Isaac Lab Documentation"
html_theme_path = [sphinx_book_theme.get_html_theme_path()]
html_theme = "sphinx_book_theme"
html_title = "Isaac Lab"
html_theme = "nvidia_sphinx_theme"
html_favicon = "source/_static/favicon.ico"
html_show_copyright = True
html_show_sphinx = False
Expand All @@ -243,56 +241,59 @@
html_static_path = ["source/_static/css"]
html_css_files = ["custom.css"]

html_context = {
"github_user": "isaac-sim",
"github_repo": "IsaacLab",
"github_version": "main",
"doc_path": "docs",
}
html_theme_options = {
"path_to_docs": "docs/",
"pygments_light_style": "tango",
"pygments_dark_style": "monokai",
"collapse_navigation": True,
"repository_url": "https://github.com/isaac-sim/IsaacLab",
"use_repository_button": True,
"use_issues_button": True,
"copyright_override": {"start": 2022},
"github_url": "https://github.com/isaac-sim/IsaacLab",
"secondary_sidebar_items": ["page-toc", "edit-this-page"],
"use_edit_page_button": True,
"show_toc_level": 1,
"use_sidenotes": True,
"logo": {
"text": "Isaac Lab Documentation",
"image_light": "source/_static/NVIDIA-logo-white.png",
"image_dark": "source/_static/NVIDIA-logo-black.png",
"navigation_depth": 2,
"switcher": {
"json_url": "https://isaac-sim.github.io/IsaacLab/main/_static/switcher.json",
"version_match": os.environ.get("SMV_CURRENT_VERSION", "main"),
},
"check_switcher": False, # Disable switcher check during local builds
"icon_links": [
{
"name": "GitHub",
"url": "https://github.com/isaac-sim/IsaacLab",
"icon": "fa-brands fa-square-github",
"name": "Docker",
"url": "https://catalog.ngc.nvidia.com/orgs/nvidia/containers/isaac-lab",
"icon": "fa-brands fa-docker",
"type": "fontawesome",
},
{
"name": "Isaac Sim",
"url": "https://developer.nvidia.com/isaac-sim",
"icon": "https://img.shields.io/badge/IsaacSim-5.1.0-silver.svg",
"type": "url",
},
{
"name": "Stars",
"url": "https://img.shields.io/github/stars/isaac-sim/IsaacLab?color=fedcba",
"icon": "https://img.shields.io/github/stars/isaac-sim/IsaacLab?color=fedcba",
"type": "url",
"name": "PyPI",
"url": "https://pypi.org/project/isaaclab",
"icon": "fa-brands fa-python",
"type": "fontawesome",
},
],
"icon_links_label": "Quick Links",
"footer_links": {},
}

templates_path = [
"_templates",
]

# Whitelist pattern for remotes
# -- Sphinx-multiversion configuration --------------------------------------

# Whitelist pattern for remotes (branches/tags from which remote to include)
smv_remote_whitelist = r"^.*$"
# Whitelist pattern for branches (set to None to ignore all branches)
smv_branch_whitelist = os.getenv("SMV_BRANCH_WHITELIST", r"^(main|devel|release/.*)$")
smv_branch_whitelist = os.getenv("SMV_BRANCH_WHITELIST", r"^(main)$")
# Whitelist pattern for tags (set to None to ignore all tags)
smv_tag_whitelist = os.getenv("SMV_TAG_WHITELIST", r"^v[1-9]\d*\.\d+\.\d+$")
html_sidebars = {
"**": ["navbar-logo.html", "versioning.html", "icon-links.html", "search-field.html", "sbt-sidebar-nav.html"]
}
# Output directory format for each version
smv_outputdir_format = "{ref.name}"
# Prefer remote refs over local refs
smv_prefer_remote_refs = False


# -- Advanced configuration -------------------------------------------------
Expand Down
130 changes: 130 additions & 0 deletions docs/generate_switcher.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#!/usr/bin/env python3
# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause

"""Generate switcher.json for version dropdown from git tags and branches."""

import json
import os
import re
import subprocess
from pathlib import Path


def get_git_tags_and_branches():
"""Get all tags and branches matching the sphinx-multiversion patterns."""
# Get tag whitelist pattern from environment or use default
tag_pattern = os.getenv("SMV_TAG_WHITELIST", r"^v[1-9]\d*\.\d+\.\d+$")
branch_pattern = os.getenv("SMV_BRANCH_WHITELIST", r"^(main)$")

versions = []

# Get all tags
try:
result = subprocess.run(["git", "tag", "-l"], capture_output=True, text=True, check=True)
tags = result.stdout.strip().split("\n")
tags = [t for t in tags if t and re.match(tag_pattern, t)]

# Sort tags by version (newest first)
def version_key(tag):
# Extract version numbers from tag like v1.2.3
match = re.match(r"^v?(\d+)\.(\d+)\.(\d+)", tag)
if match:
return tuple(int(x) for x in match.groups())
return (0, 0, 0)

tags.sort(key=version_key, reverse=True)

# remove tags older than version 2.0.2
tags = [t for t in tags if version_key(t) >= (2, 0, 2)]

for tag in tags:
version_num = tag.lstrip("v")
versions.append({
"version": version_num,
"name": f"v{version_num}",
"url": f"https://isaac-sim.github.io/IsaacLab/{tag}/",
})

except subprocess.CalledProcessError:
print("Warning: Could not get git tags")

# Mark the latest tag as stable/preferred
if versions:
versions[0]["name"] = f"{versions[0]['name']} (stable)"
versions[0]["preferred"] = True

# Get all branches
try:
result = subprocess.run(["git", "branch", "-r"], capture_output=True, text=True, check=True)
branches = result.stdout.strip().split("\n")
# Clean up branch names (remove origin/ prefix and whitespace)
branches = [b.strip().replace("origin/", "") for b in branches if b.strip()]
# Filter by pattern and exclude HEAD
branches = [b for b in branches if b and re.match(branch_pattern, b) and "HEAD" not in b]

for branch in branches:
if branch == "main":
versions.insert(
0,
{
"version": "main",
"name": "main (latest)",
"url": "https://isaac-sim.github.io/IsaacLab/main/",
},
)
elif branch == "devel":
versions.insert(
1 if "main" in [v["version"] for v in versions] else 0,
{
"version": "dev",
"name": "devel (development)",
"url": "https://isaac-sim.github.io/IsaacLab/devel/",
},
)
else:
versions.append({
"version": branch,
"name": branch,
"url": f"https://isaac-sim.github.io/IsaacLab/{branch}/",
})

except subprocess.CalledProcessError:
print("Warning: Could not get git branches")

return versions


def main():
"""Generate switcher.json file."""
# Get the docs directory
docs_dir = Path(__file__).parent
static_dir = docs_dir / "source" / "_static"
static_dir.mkdir(parents=True, exist_ok=True)

# Generate version list
versions = get_git_tags_and_branches()

if not versions:
print("Warning: No versions found!")
versions = [{
"version": "main",
"name": "main (latest)",
"url": "https://isaac-sim.github.io/IsaacLab/main/",
"preferred": True,
}]

# Write switcher.json
switcher_file = static_dir / "switcher.json"
with open(switcher_file, "w") as f:
json.dump(versions, f, indent=4)

print(f"Generated {switcher_file} with {len(versions)} versions:")
for v in versions:
print(f" - {v['name']} ({v['version']})")


if __name__ == "__main__":
main()
Loading
Loading