diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..9bf316c --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,30 @@ +name: Documentation + +on: + push: + branches: [main] + paths: + - 'docs/**' + - 'mkdocs.yml' + - 'scripts/mkdocs_gen_ref_pages.py' + - 'lib/**' + pull_request: + paths: + - 'docs/**' + - 'mkdocs.yml' + - 'scripts/mkdocs_gen_ref_pages.py' + - 'lib/**' + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.13' + - name: Install MkDocs dependencies + run: pip install -r docs/requirements.txt + - name: Build documentation + run: mkdocs build diff --git a/.gitignore b/.gitignore index d9561f8..a75fff4 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ VERSION tools/sourcey-api/node_modules/ tools/sourcey-api/dist/ site/ +.venv-docs/ diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..4b81448 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,13 @@ +version: 2 + +build: + os: ubuntu-24.04 + tools: + python: "3.13" + +mkdocs: + configuration: mkdocs.yml + +python: + install: + - requirements: docs/requirements.txt diff --git a/AGENTS.md b/AGENTS.md index 1568bc0..5f50512 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -46,3 +46,10 @@ from the cmods workspace root when the usermod is linked into those interpreters Font C headers: `python3 scripts/sync_fonts.py` (source of truth is `lib/pygraphics/_font_8x*.py`). + +## Documentation + +- MkDocs under `docs/` → https://pygraphics.readthedocs.io (`.readthedocs.yaml`) +- Sourcey native API under `tools/sourcey-api/` → Pages `/api/` +- Local: `python3 -m venv .venv-docs && .venv-docs/bin/pip install -r docs/requirements.txt && .venv-docs/bin/mkdocs serve` + diff --git a/README.md b/README.md index cca4bdc..dad2771 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# graphics +# pygraphics -Native and pure-Python **graphics** for MicroPython, CircuitPython, and CPython. +Native and pure-Python **pygraphics** for MicroPython, CircuitPython, and CPython. Import as `pygraphics`. | Product | Pip / MIP | Role | @@ -58,6 +58,7 @@ print(pygraphics.implementation()) # native_cmod or pygraphics_python ## Links +- [Documentation](https://pygraphics.readthedocs.io) - [Source-linked API reference](https://pydevices.github.io/pygraphics/api/) - [Source](https://github.com/PyDevices/pygraphics) - [Issues](https://github.com/PyDevices/pygraphics/issues) @@ -74,7 +75,7 @@ MIT (framebuf algorithms derived from MicroPython `extmod/modframebuf.c`, Damien ### Layout ``` -graphics/ +pygraphics/ micropython.mk / micropython.cmake / circuitpython.mk / setup.py src/ # C sources + headers (gfx_*.h, font_8x*.h, qstrs) lib/pygraphics/ # pure-Python package (import pygraphics) diff --git a/docs/README.md b/docs/README.md index f555e76..83ac95a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,20 +1,14 @@ -# API reference site +# Documentation -This directory contains the reproducible Sourcey reference for the native -`pygraphics` module. The generator reads the CPython binding tables and public C -headers at the checked-out commit, then emits source-linked Markdown for the -Python and native integration surfaces. +Hand-authored MkDocs pages live in this directory and publish to +[pygraphics.readthedocs.io](https://pygraphics.readthedocs.io). ```bash -cd docs -npm ci -npm run check +python3 -m venv .venv-docs +.venv-docs/bin/pip install -r docs/requirements.txt +.venv-docs/bin/mkdocs serve # or: mkdocs build ``` -`npm run check` regenerates the reference, builds the static site into `dist/`, -and verifies API coverage, immutable source links, project-scoped search URLs, -canonical URLs, and integration with the existing Pages deployment. Generated -HTML remains untracked build output. - -The existing Pages workflow preserves the project homepage and publishes the -Sourcey build below `/pygraphics/api/` after a merge to `main`. +The native (C) source-linked API is built separately with Sourcey under +[`tools/sourcey-api/`](../tools/sourcey-api/) and deployed to +[pydevices.github.io/pygraphics/api/](https://pydevices.github.io/pygraphics/api/). diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md new file mode 100644 index 0000000..5b85889 --- /dev/null +++ b/docs/SUMMARY.md @@ -0,0 +1,5 @@ +* [Home](index.md) +* [Getting started](getting-started.md) +* [Installation](installation.md) +* [Publishing](publishing.md) +* [API Reference](reference/) diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 0000000..6d6d025 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,40 @@ +# Getting started + +## Setup + +Install from [MIP](installation.md) or [TestPyPI](installation.md): + +```python +import mip +mip.install("pygraphics", index="https://PyDevices.github.io/micropython-lib/mip/PyDevices") +``` + +Development clone — put `lib/` on `PYTHONPATH`, or `pip install -e .` for the +native cmod. + +## Basic usage + +```python +import pygraphics +from pygraphics import FrameBuffer, RGB565, Area + +fb = FrameBuffer(bytearray(160 * 128 * 2), 160, 128, RGB565) +fb.fill(0) +area = fb.fill_rect(10, 10, 40, 40, 0xF800) +assert isinstance(area, Area) +print(pygraphics.implementation()) # native_cmod or pygraphics_python +``` + +## What you get + +- `Area` — rectangle geometry for dirty regions / clipping +- `FrameBuffer` — framebuf-compatible surface; draw methods return `Area` +- Format constants: `MONO_*`, `RGB565`, `GS*`, `RGB888` +- `Draw`, `Font`, BMP565 / PBM / PGM helpers +- `framebuf_backend()`, `capabilities()`, `implementation()` + +## Examples + +Drawing demos live in +[pydisplay `src/examples/`](https://github.com/PyDevices/pydisplay/tree/main/src/examples) +(`graphics_simpletest.py`, BMP565 samples, and others). diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..1747451 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,22 @@ +# pygraphics + +**pygraphics** is the cross-platform 2D drawing package for the PyDevices stack — +`Area`, framebuf-compatible `FrameBuffer`, fonts, shapes, and image loaders for +MicroPython, CircuitPython, and CPython. + +| Product | Channel | Role | +|---------|---------|------| +| **pygraphics-cmod** | TestPyPI | All-C extension (`implementation()` → `native_cmod`) | +| **pygraphics** | TestPyPI + MIP | Pure-Python package (`pygraphics_python`) | + +Same public API either way. Prefer the cmod on desktop/Android when a matching +wheel is available. + +## Links + +- [Getting started](getting-started.md) +- [Installation](installation.md) +- [API Reference](reference/pygraphics/index.md) +- [Native source-linked API (Pages)](https://pydevices.github.io/pygraphics/api/) +- [pydisplay documentation](https://pydisplay.readthedocs.io) +- [GitHub](https://github.com/PyDevices/pygraphics) diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..bb35292 --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,47 @@ +# Installation + +## MicroPython (MIP) + +```python +import mip +mip.install("pygraphics", index="https://PyDevices.github.io/micropython-lib/mip/PyDevices") +``` + +The package path on micropython-lib is `micropython/pygraphics/` (import name +`pygraphics`). Older installs that used MIP name `graphics` should reinstall +under the new name after the next publish. + +## CircuitPython / copy install + +Copy the `pygraphics/` package folder onto `sys.path` (from +`lib/pygraphics/` in this repo, or from micropython-lib). + +## CPython — native (preferred when available) + +```bash +pip install \ + -i https://test.pypi.org/simple/ \ + --extra-index-url https://pypi.org/simple/ \ + pygraphics-cmod +``` + +## CPython — pure Python + +```bash +pip install \ + -i https://test.pypi.org/simple/ \ + --extra-index-url https://pypi.org/simple/ \ + pygraphics +``` + +## Name cutover + +| Role | Current | Retired (do not use) | +|------|---------|----------------------| +| Import | `pygraphics` | `graphics` | +| Pure-Python pip | `pygraphics` | `pydisplay-graphics` | +| Native pip | `pygraphics-cmod` | `graphics-cmod` | +| MIP | `pygraphics` | `graphics` | + +TestPyPI may still list the old project names until they age out; install the +**current** names above. diff --git a/docs/PUBLISHING.md b/docs/publishing.md similarity index 76% rename from docs/PUBLISHING.md rename to docs/publishing.md index ff01fdb..ab314a0 100644 --- a/docs/PUBLISHING.md +++ b/docs/publishing.md @@ -10,17 +10,17 @@ One annotated tag `vX.Y.Z` publishes **both** products at that version: ## Pipeline ```text -graphics (commit on main) +pygraphics (commit on main) ./scripts/publish_release_tag.sh --push # next patch after highest v* │ ├─► publish-testpypi.yml │ cibuildwheel → Linux + Windows + Android → pygraphics-cmod │ └─► publish-micropython-lib.yml - sync → micropython/graphics/ + sync → micropython/pygraphics/ hatch + twine → pygraphics rebuild mip/PyDevices → gh-pages - remove legacy micropython/pydisplay/graphics/ + remove legacy micropython/graphics/ and pydisplay/graphics/ ``` ## Version numbers @@ -43,7 +43,7 @@ release is **`v0.0.25`** (not `v0.0.11`). Later tags continue from the highest | `TESTPYPI_API_TOKEN` | TestPyPI upload (cmod + pygraphics) | | `MICROPYTHON_LIB_DEPLOY_TOKEN` | PAT with `contents:write` on PyDevices/micropython-lib | -Grant both secrets to the **graphics** repository (org secret repository access). +Grant both secrets to the **pygraphics** repository (org secret repository access). ## Install @@ -67,3 +67,10 @@ python3 -m venv .venv .venv/bin/pip install -e . .venv/bin/python tests/test_pygraphics.py ``` + +## Documentation + +- **Read the Docs** (guides + pure-Python API): https://pygraphics.readthedocs.io + Config: `.readthedocs.yaml` + `mkdocs.yml`. Import the GitHub repo once in the + RTD dashboard with slug `pygraphics` if the project is not live yet. +- **GitHub Pages** (marketing + Sourcey native API): https://pydevices.github.io/pygraphics/ diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..011885f --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,7 @@ +mkdocs>=1.6 +mkdocs-material>=9.5 +mkdocstrings[python]>=0.26 +mkdocs-gen-files>=0.5 +mkdocs-literate-nav>=0.6 +mkdocs-section-index>=0.3 +mkdocs-jupyter>=0.25 diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css new file mode 100644 index 0000000..a17fb03 --- /dev/null +++ b/docs/stylesheets/extra.css @@ -0,0 +1,56 @@ +/* + * PyDevices brand colors for Material for MkDocs. + * Tokens mirror https://pydevices.github.io/assets/css/site.css + */ + +:root > * { + --md-primary-fg-color: #f54e00; + --md-primary-fg-color--light: #ff7a3d; + --md-primary-fg-color--dark: #c33f00; + --md-primary-bg-color: #fff7f1; + --md-primary-bg-color--light: rgba(255, 247, 241, 0.7); + + --md-accent-fg-color: #ff7a3d; + --md-accent-fg-color--transparent: rgba(245, 78, 0, 0.1); + --md-accent-bg-color: #1a0d05; + --md-accent-bg-color--light: rgba(26, 13, 5, 0.7); +} + +[data-md-color-scheme="default"] { + --md-default-bg-color: #fbf9f5; + --md-default-bg-color--light: #f3eee6; + --md-default-bg-color--lighter: #f6f1e9; + --md-default-bg-color--lightest: #ffffff; + --md-default-fg-color: #201c16; + --md-default-fg-color--light: #5b5347; + --md-default-fg-color--lighter: #8a8172; + --md-default-fg-color--lightest: #c9bfae; + --md-typeset-a-color: #c33f00; + --md-code-bg-color: #f6f1e9; + --md-code-fg-color: #201c16; + --md-footer-bg-color: #f3eee6; + --md-footer-bg-color--dark: #201c16; + --md-footer-fg-color: #201c16; + --md-footer-fg-color--light: #5b5347; + --md-footer-fg-color--lighter: #8a8172; +} + +[data-md-color-scheme="slate"] { + --md-hue: 32; + --md-default-bg-color: #100e0b; + --md-default-bg-color--light: #17130f; + --md-default-bg-color--lighter: #1c1712; + --md-default-bg-color--lightest: #241e17; + --md-default-fg-color: #f3ecdf; + --md-default-fg-color--light: #c9bfae; + --md-default-fg-color--lighter: #8f8474; + --md-default-fg-color--lightest: #5b5347; + --md-typeset-a-color: #ff8a52; + --md-code-bg-color: #1c1712; + --md-code-fg-color: #f3ecdf; + --md-footer-bg-color: #17130f; + --md-footer-bg-color--dark: #100e0b; + --md-footer-fg-color: #f3ecdf; + --md-footer-fg-color--light: #c9bfae; + --md-footer-fg-color--lighter: #8f8474; +} diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..5922308 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,53 @@ +site_name: pygraphics +site_url: https://pygraphics.readthedocs.io +repo_url: https://github.com/PyDevices/pygraphics/ +edit_uri: edit/main/docs/ +copyright: "Copyright 2024, Brad Barnett" +docs_dir: docs +site_dir: site + +theme: + name: material + palette: + - scheme: default + primary: custom + accent: custom + toggle: + icon: material/brightness-7 + name: Switch to dark mode + - scheme: slate + primary: custom + accent: custom + toggle: + icon: material/brightness-4 + name: Switch to light mode + features: + - navigation.sections + - navigation.top + - search.suggest + - content.code.copy + +extra_css: + - stylesheets/extra.css + +plugins: + - search + - gen-files: + scripts: + - scripts/mkdocs_gen_ref_pages.py + - literate-nav: + nav_file: SUMMARY.md + - section-index + - mkdocstrings: + handlers: + python: + paths: [lib] + options: + show_source: false + show_root_heading: true + show_symbol_type_heading: true + show_symbol_type_toc: true + docstring_style: google + merge_init_into_class: true + filters: + - "!^_" diff --git a/scripts/mkdocs_gen_ref_pages.py b/scripts/mkdocs_gen_ref_pages.py new file mode 100644 index 0000000..cd4bbfa --- /dev/null +++ b/scripts/mkdocs_gen_ref_pages.py @@ -0,0 +1,37 @@ +"""Generate mkdocstrings API reference stubs and navigation for pygraphics.""" + +from pathlib import Path + +import mkdocs_gen_files + +nav = mkdocs_gen_files.Nav() +root = Path(__file__).parent.parent +lib = root / "lib" +reference = Path("reference") + +for path in sorted((lib / "pygraphics").rglob("*.py")): + if path.name.startswith("_") and path.name != "__init__.py": + continue + module_path = path.relative_to(lib).with_suffix("") + doc_path = module_path.with_suffix(".md") + full_doc_path = reference / doc_path + + parts = tuple(module_path.parts) + + if parts[-1] == "__init__": + parts = parts[:-1] + doc_path = doc_path.with_name("index.md") + full_doc_path = full_doc_path.with_name("index.md") + elif parts[-1] == "__main__": + continue + + nav[parts] = doc_path.as_posix() + + with mkdocs_gen_files.open(full_doc_path, "w") as fd: + ident = ".".join(parts) + fd.write(f"::: {ident}\n") + + mkdocs_gen_files.set_edit_path(full_doc_path, path.relative_to(root)) + +with mkdocs_gen_files.open("reference/SUMMARY.md", "w") as nav_file: + nav_file.writelines(nav.build_literate_nav()) diff --git a/scripts/publish_micropython_lib.sh b/scripts/publish_micropython_lib.sh index 39481f6..69a285b 100755 --- a/scripts/publish_micropython_lib.sh +++ b/scripts/publish_micropython_lib.sh @@ -161,12 +161,16 @@ metadata( package("$BASENAME") EOF -# Retire the legacy pydisplay/graphics tree after extraction. -LEGACY_DIR="$DEST_REPO/micropython/pydisplay/graphics" -LEGACY_DIR2="$DEST_REPO/micropython/graphics" -if [[ -d "$LEGACY_DIR" ]]; then - rm -rf "$LEGACY_DIR" -fi +# Retire legacy package trees after the rename/extraction. +for LEGACY_DIR in \ + "$DEST_REPO/micropython/pydisplay/graphics" \ + "$DEST_REPO/micropython/graphics" +do + if [[ -d "$LEGACY_DIR" ]]; then + echo "Removing legacy tree $LEGACY_DIR" + rm -rf "$LEGACY_DIR" + fi +done cp "$README_FULL_PATH" "$DEST_DIR/README.md" diff --git a/web/index.html b/web/index.html index 8d86fb0..98941cd 100644 --- a/web/index.html +++ b/web/index.html @@ -4,7 +4,7 @@ -
Native all-C pygraphics-cmod and pure-Python pygraphics (lib/pygraphics/) for MicroPython, CircuitPython, and CPython. Same public API either way: Area, framebuf-compatible FrameBuffer, format constants, plus framebuf_backend(), capabilities(), and implementation().
One release tag publishes both products. Prefer the cmod when linked or installed (implementation() → native_cmod); otherwise use TestPyPI pygraphics or MIP graphics (pygraphics_python).
One release tag publishes both products. Prefer the cmod when linked or installed (implementation() → native_cmod); otherwise use TestPyPI pygraphics or MIP pygraphics (pygraphics_python).