diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 0a9ad9c..39b7837 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,5 +1,5 @@ # Keep pinned GitHub Actions current. Nothing else here is managed by -# Dependabot: Python dependencies are pinned per docs/requirements.txt or +# Dependabot: Python dependencies are # resolved at build time, not from a lockfile in this repo. version: 2 updates: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..b0bf4cc --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,50 @@ +# Contributing + +Bug reports and fixes are welcome. Open an +[issue](https://github.com/PyDevices/pyscript-template/issues) first for +anything larger than a fix. + +## Run the tests + +```bash +./scripts/vendor_pyscript.sh +python3 -m unittest discover -s tests -v +``` + +The suite checks that the shell, service worker, manifest and `pyscript.json` +agree: the JSON parses, every local file `index.html` and `sw.js` mention +exists, the PyDevices source URLs are pinned to the release the test names, the +page uses the Pyodide interpreter, and `pwa.js` leaves the browser's own install +prompt alone. Two tests also run `tests/worklet_sim.mjs` under Node to check the +audio worklet's queue. It does not replace a real browser test of pointer +input, installation or offline caching. + +Read `tests/test_template.py` before moving a shell file or adding a generated +asset to the cache list. + +## Update a pin + +- **PyScript.** Change `PYSCRIPT_VERSION` in `scripts/vendor_pyscript.sh`. + Check and confirm + `https://pyscript.net/releases//offline_.zip` returns 200 + before committing. Re-run `./scripts/vendor_pyscript.sh` and the tests. + The wheel tag in [Bring in a bigger + app](docs/guides/bring-in-a-bigger-app.md) depends on the Pyodide that + release ships. +- **PyDevices sources.** Every URL in `pyscript.json` names one PyDevices + release. Change them together and update the release string in + `tests/test_template.py`, then load the app in a browser. +- **Cache.** Change `VERSION` in `sw.js` whenever you change a cached file, so + browsers that already have the app pick the change up. + +## Docs + +The pages are plain Markdown under `docs/`, starting at +[docs/index.md](docs/index.md). There is no docs build. Check that any link you +add resolves. + +## Releasing + +The template has no packages and no version of its own: a change is released +by merging it to `main`, and users get it the next time they press **Use this +template** or pull. diff --git a/README.md b/README.md index 06a376c..f887eac 100644 --- a/README.md +++ b/README.md @@ -1,112 +1,50 @@ -# PyDevices PyScript template +![The paint demo running in a browser: a row of colour blocks above a canvas with four coloured wavy lines](docs/images/paint.png) -A minimal, installable PyScript application for the portable -[PyDevices](https://github.com/PyDevices/pydevices) display stack. +# PyScript template -Use this repository as a GitHub template, edit `main.py`, and run it on your -own machine with Python's built-in web server ([below](#run-it-locally)). The -service worker caches the application shell and the pinned PyScript -interpreter, so after one visit the app launches offline too. The template -pins PyDevices source files to release `v0.7.0`, so a new app does not -silently change when the product's default branch advances. +PyScript template is a starter for an installable browser app that draws with +the PyDevices display stack: Python (Pyodide) on a canvas, working offline once +it has loaded. -## Starter Example: Interactive Touch / Paint +On GitHub, press **Use this template**, or clone it, then serve it from +localhost: -This is exactly what ships in `main.py` — an interactive paint application -demonstrating the PyDevices Board Contract (`board_config` and -`appdev.App`) running in the browser: - -```python -import board_config -import appdev +```bash +git clone https://github.com/PyDevices/pyscript-template my-app +cd my-app +./scripts/vendor_pyscript.sh +python3 -m http.server 8000 +``` -display_drv = board_config.display_drv -app = appdev.App(board_config) +Open . Here is a paint app in 20 lines; it is a cut-down +`main.py`, which also sets a 500x500 display size: +```python +import board_config, appdev +from pyscript import document +display, app = board_config.display_drv, appdev.App(board_config) colors = [0xFFFF, 0xF800, 0x07E0, 0x001F, 0x07FF, 0xF81F, 0xFFE0, 0x0000] -block_size = display_drv.width // len(colors) -selected = 0 - -def draw_palette(): - for i, color in enumerate(colors): - x = i * block_size - display_drv.fill_rect(x, 0, block_size, 30, color) - display_drv.show() - -draw_palette() - +block, selected = display.width // len(colors), 0 +for i, color in enumerate(colors): + display.fill_rect(i * block, 0, block, 30, color) +display.show() +document.querySelector("#status").textContent = "Pick a colour, then paint." def on_touch(event): global selected x, y = event.pos if y < 30: - selected = min(len(colors) - 1, x // block_size) + selected = min(len(colors) - 1, x // block) else: - display_drv.fill_rect(x - 3, y - 3, 6, 6, colors[selected]) - display_drv.show() - + display.fill_rect(x - 3, y - 3, 6, 6, colors[selected]) + display.show() app.on(app.events.MOUSEBUTTONDOWN, on_touch) app.on(app.events.MOUSEMOTION, on_touch) app.run() ``` -## How It Works - -1. **HTML5 Canvas Backend**: `board_config.display_drv` binds to the `` element through the supported PyScript/Pyodide `PSDisplay` backend. This template is intentionally Pyodide-only; direct MicroPython WebAssembly applications use the Gallery host instead. -2. **Browser Event Loop**: `app.run()` integrates cooperatively with the browser's native JavaScript event loop to dispatch pointer/touch events. -3. **Installable and offline**: the service worker caches the PyScript interpreter and application shell, so the app installs and runs offline on desktop and mobile browsers. A small note near the top right tells visitors how their browser installs it, and an installed app opens in a window sized to the display `board_config` asks for. [The PWA guide](docs/pwa-guide.md) has the details. - -## Documentation - -- [Newcomer's guide](docs/newcomers.md) — how the template becomes a browser app, and which generated boundaries to preserve. -- [Make your PyScript app a PWA](docs/pwa-guide.md) — where it installs, the - manifest, the service worker, the app window, and edits that don't show. - The template already ships everything that guide describes. - -What's planned next is in [ROADMAP.md](ROADMAP.md). - -## Customize - -- Edit `main.py` for application behavior. -- Edit `pyscript.json` to add PyDevices source files or Pyodide packages. For - an app that makes sound or uses LVGL, such as piano or the drum machine from - pydevices-examples, see [Bringing in a bigger app](docs/packages.md). -- Change the app name, colors, and icons in `index.html`, `manifest.json`, and `style.css`. -- Change `PYSCRIPT_VERSION` in `scripts/vendor_pyscript.sh` when you choose to - update the browser interpreter. Check the - [PyScript releases page](https://github.com/pyscript/pyscript/releases) or - for newer versions before bumping the pin, - and confirm `https://pyscript.net/releases//offline_.zip` - returns 200 before committing the change. - -## Run it locally - -From the repository root: - -```bash -./scripts/vendor_pyscript.sh -python3 -m http.server 8000 -``` - -Then open . The first command downloads the pinned -PyScript release into `vendor/` (it is `.gitignore`d, so run it once per -checkout and again after you change the pin). - -Use that `localhost` address rather than opening `index.html` from disk or -browsing to the machine's LAN IP. Service workers, which make the app -installable and offline, only run on `http://localhost` or over `https://`. - -The service worker serves every file from its cache once it has one, so an -edit to `main.py` can look as if it did nothing. While you work, reload with -**Ctrl+Shift+R** (**Cmd+Shift+R** on a Mac), or open DevTools → Application → -Service workers and tick **Bypass for network**. [Edits that don't -show](docs/pwa-guide.md#edits-that-dont-show) has the rest. - -## Verify - -```bash -python3 -m unittest discover -s tests -v -``` +Click a colour block along the top, then move the pointer over the canvas to +paint. The picture at the top of this page is that app after four strokes. -The template uses only the `py` interpreter (Pyodide) for the broadest pip-wheel path. The same PyDevices source packages remain portable to MicroPython, CircuitPython, and CPython desktop; use the [direct MicroPython WebAssembly Gallery](https://pydevices.github.io/pydevices-examples/gallery/) for the first-party direct host and complete cross-interpreter examples. +[Docs](https://github.com/PyDevices/pyscript-template/blob/main/docs/index.md) · [Examples](https://pydevices.github.io/pydevices-examples/gallery/) · [Roadmap](ROADMAP.md) -MIT licensed. See `LICENSE`. +Made by [PyDevices](https://pydevices.com). diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index f4d37ba..0000000 --- a/docs/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Documentation - -- [Newcomer's guide](newcomers.md) — codebase map, browser execution path, and safe customization. -- [Bringing in a bigger app](packages.md) — wheels for sound, pygraphics and - LVGL; piano and the drum machine as worked examples. -- [Make your PyScript app a PWA](pwa-guide.md) — where it installs, the - manifest and service worker, the app window, running it locally, and edits - that don't show. - -Start with the [root README](../README.md) for the template itself. -- [workers.md](workers.md): run your Python in Web Workers when the main thread has to stay free (Web MIDI, live audio) diff --git a/docs/get-started/index.md b/docs/get-started/index.md new file mode 100644 index 0000000..4e0da32 --- /dev/null +++ b/docs/get-started/index.md @@ -0,0 +1,49 @@ +# Make your first app + +## Use the template + +On GitHub, press **Use this template** on the +[pyscript-template](https://github.com/PyDevices/pyscript-template) +page to make your own repository, or clone it: + +```bash +git clone https://github.com/PyDevices/pyscript-template my-app +cd my-app +``` + +## Run it locally + +From the repository root: + +```bash +./scripts/vendor_pyscript.sh +python3 -m http.server 8000 +``` + +Then open . The first command downloads the pinned +PyScript release into `vendor/` (it is `.gitignore`d, so run it once per +checkout and again after you change the pin). You should see a row of eight +colour blocks above a black canvas. Click a block, then click or drag on the +canvas to paint. + +Use that `localhost` address rather than opening `index.html` from disk or +browsing to the machine's LAN IP. Service workers, which make the app +installable and offline, only run on `http://localhost` or over `https://`. + +The service worker serves every file from its cache once it has one, so an +edit to `main.py` can look as if it did nothing. While you work, reload with +**Ctrl+Shift+R** (**Cmd+Shift+R** on a Mac), or open DevTools, Application, +Service workers and tick **Bypass for network**. [Edits that don't +show](../guides/make-it-installable.md#edits-that-dont-show) has the rest. + +## Make it yours + +1. Edit `main.py` to replace the paint demo with your application. +2. Rename the app in `index.html` and `manifest.json`, replace the two icons + and adjust `style.css`. +3. Add only the PyDevices source files or Pyodide packages the app needs to + `pyscript.json`. For an app that makes sound or uses LVGL, see + [Bring in a bigger app](../guides/bring-in-a-bigger-app.md). +4. Install it from Chrome or Edge on localhost, check that its window fits the + display, and check that it launches with the server stopped. The steps are in + [Make your app installable and offline](../guides/make-it-installable.md). diff --git a/docs/packages.md b/docs/guides/bring-in-a-bigger-app.md similarity index 98% rename from docs/packages.md rename to docs/guides/bring-in-a-bigger-app.md index 232da8c..c349453 100644 --- a/docs/packages.md +++ b/docs/guides/bring-in-a-bigger-app.md @@ -9,7 +9,7 @@ worked examples. ## Use the pydevices wheel instead of the file list -`audiodev` alone is fourteen files, so stop listing sources one by one. +`audiodev` alone is a dozen or more files, so stop listing sources one by one. PyScript's `packages` takes wheel URLs, and the `pydevices` wheel carries the whole core (`displaydev`, `audiodev`, `appdev`, `events`, `keys`, `multimer`). Two files still come from the source tree: the browser board diff --git a/docs/pwa-guide.md b/docs/guides/make-it-installable.md similarity index 89% rename from docs/pwa-guide.md rename to docs/guides/make-it-installable.md index d7c6275..512d099 100644 --- a/docs/pwa-guide.md +++ b/docs/guides/make-it-installable.md @@ -1,4 +1,4 @@ -# Progressive Web App (PWA) Guide for PyScript +# Make your app installable and offline This template is already an installable, offline-capable app. Your PyScript application can: @@ -43,7 +43,7 @@ All of this lives at the repository root: ### The manifest -[`manifest.json`](../manifest.json) tells the browser how the app appears +[`manifest.json`](../../manifest.json) tells the browser how the app appears once installed. `display: "standalone"` gives it a window with no address bar, `theme_color` colours the title bar, `background_color` is the splash screen, and the two icons cover home screens and launchers. Change the names, colours @@ -54,7 +54,7 @@ The manifest can't say how big the window should be; there is no such member. ### The service worker -[`sw.js`](../sw.js) caches the shell (`SHELL`) when it installs, then serves +[`sw.js`](../../sw.js) caches the shell (`SHELL`) when it installs, then serves every GET request from its cache first and caches anything new it fetches. On the first visit the page starts loading before the worker controls it, so `pwa.js` also hands the worker the URLs the page already loaded and the worker @@ -92,20 +92,9 @@ Browsers decide whether a page may resize its window: In a tab, `pwa.js` never touches the window. -## Run it locally +## Serve it from localhost -From the repository root: - -```bash -./scripts/vendor_pyscript.sh -python3 -m http.server 8000 -``` - -Open . A service worker only runs on a secure origin: -`http://localhost` counts, `https://` counts, and a file opened from disk or a -LAN address like `http://192.168.1.20:8000` doesn't. On localhost Chrome and -Edge show their install icon, so you can install the app and try its window -from your own machine. +[Run it locally](../get-started/index.md#run-it-locally) has the commands. A service worker only runs on a secure origin: `http://localhost` counts, `https://` counts, and a file opened from disk or a LAN address like `http://192.168.1.20:8000` doesn't. On localhost Chrome and Edge show their install icon, so you can install the app and try its window from your own machine. ### Edits that don't show diff --git a/docs/workers.md b/docs/guides/run-in-a-worker.md similarity index 99% rename from docs/workers.md rename to docs/guides/run-in-a-worker.md index 36d4e62..f3aa381 100644 --- a/docs/workers.md +++ b/docs/guides/run-in-a-worker.md @@ -1,4 +1,4 @@ -# Python in Web Workers +# Run your Python in Web Workers By default the template runs your Python on the page's main thread, which is simple and fine for most apps. When your app redraws a lot *and* has to diff --git a/docs/newcomers.md b/docs/how-it-works/index.md similarity index 61% rename from docs/newcomers.md rename to docs/how-it-works/index.md index d4f2431..c61d3d4 100644 --- a/docs/newcomers.md +++ b/docs/how-it-works/index.md @@ -1,4 +1,4 @@ -# Newcomer's guide to the PyDevices PyScript template +# How the template works This repository is a GitHub template for an installable browser application, not a shared PyDevices library. Start by using the template to create your own @@ -38,23 +38,7 @@ sw.js caches the shell and later GET responses for offline reuse The application must be served over HTTP. Opening `index.html` directly from the filesystem does not provide the origin that PyScript needs, and the service worker only runs on `http://localhost` or `https://`. The root -README's [Run it locally](../README.md#run-it-locally) has the commands. - -## Repository map - -| Path | Purpose | -|---|---| -| `index.html` | Application shell: canvas, status text, PyScript loader, and the Python entrypoint declaration. | -| `main.py` | Starter Python application. It constructs `appdev.App(board_config)`, paints the demo, and handles pointer events. | -| `pyscript.json` | Exact remote-file map for the PyDevices modules available to PyScript. | -| `manifest.json` | Browser PWA identity: names, icons, scope, and display mode. | -| `pwa.js` | Registers the service worker, sizes an installed app's window to the display, and shows the note that says how to install. | -| `sw.js` | Caches the app shell and runtime, then caches successful GET responses for offline reuse. | -| `style.css` | Shell and canvas presentation. | -| `scripts/vendor_pyscript.sh` | Downloads the pinned offline PyScript release into generated `vendor/pyscript/`. | -| `.github/workflows/tests.yml` | Vendors PyScript and runs the template's unit tests. | -| `tests/test_template.py` | Checks JSON, source pins, local shell assets, and the Pyodide-only contract. | -| `docs/pwa-guide.md` | Where the app installs, the service worker's cache, the app window, and edits that don't show. | +[Run it locally](../get-started/index.md#run-it-locally) has the commands. The files, one by one, are in [Files in the template](../reference/files.md). ## Follow the starter application @@ -88,44 +72,18 @@ that is the target runtime. (Ctrl+Shift+R) or tick DevTools' **Bypass for network** when a browser appears to serve an old file, and change `VERSION` in `sw.js` when you want browsers that already have the app to pick up a change. See - [Edits that don't show](pwa-guide.md#edits-that-dont-show). + [Edits that don't show](../guides/make-it-installable.md#edits-that-dont-show). - Keep the app at the repository root. The service worker's scope and its cached paths assume it. - Browser installation and offline behavior need `http://localhost` or an `https://` origin and at least one successful online load. They cannot be proven by opening a file from disk. -## Start a safe application change - -For normal work in a repository created from this template: - -1. Edit `main.py` to replace the paint demo with your application behavior. -2. Rename the app in `index.html` and `manifest.json`; replace the icons and - adjust `style.css` as needed. -3. Add only the PyDevices source files or Pyodide packages the app needs to - `pyscript.json`. -4. Run the local HTTP preview described in the root README; do not use a - `file:` URL. -5. Install it from Chrome or Edge on localhost and check that its window fits - the display and that it launches with the server stopped. - -The template tests can be run with: - -```bash -python3 -m unittest discover -s tests -v -``` - -The test suite vendors PyScript if necessary, then verifies that the shell, -service worker, manifest, and configuration agree. It does not replace a real -browser test of pointer input, installation, or offline caching. - ## Where to learn next - Read `main.py` and `pyscript.json` together for the Python application boundary and pinned dependency set. -- Read [the PWA guide](pwa-guide.md) before changing service-worker behavior, +- Read [Make your app installable and offline](../guides/make-it-installable.md) before changing service-worker behavior, caching, the app window, or installation instructions. -- Read `tests/test_template.py` before moving a shell file or adding a generated - asset to the cache list. - For display/event APIs, follow the linked PyDevices source release rather than copying its implementation into this template. diff --git a/docs/images/paint.png b/docs/images/paint.png new file mode 100644 index 0000000..7aac8e2 Binary files /dev/null and b/docs/images/paint.png differ diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..87d5d2a --- /dev/null +++ b/docs/index.md @@ -0,0 +1,24 @@ +# PyScript template docs + +Start with [Get started](get-started/index.md) to make your own copy and see it +run, then pick a guide for what you want to change. + +**Get started** + +- [Make your first app](get-started/index.md): use the template, run it on localhost, edit `main.py`. + +**Guides** + +- [Make your app installable and offline](guides/make-it-installable.md) +- [Bring in a bigger app](guides/bring-in-a-bigger-app.md) +- [Run your Python in Web Workers](guides/run-in-a-worker.md) + +**Reference** + +- [Files in the template](reference/files.md) + +**How it works** + +- [How the template works](how-it-works/index.md) + +Building on the template's own code is covered in [CONTRIBUTING.md](../CONTRIBUTING.md). diff --git a/docs/reference/files.md b/docs/reference/files.md new file mode 100644 index 0000000..4ac6d27 --- /dev/null +++ b/docs/reference/files.md @@ -0,0 +1,15 @@ +# Files in the template + +| Path | Purpose | +|---|---| +| `index.html` | Application shell: canvas, status text, PyScript loader, and the Python entrypoint declaration. | +| `main.py` | Starter Python application. It constructs `appdev.App(board_config)`, paints the demo, and handles pointer events. | +| `pyscript.json` | Exact remote-file map for the PyDevices modules available to PyScript. | +| `manifest.json` | Browser PWA identity: names, icons, scope, and display mode. | +| `pwa.js` | Registers the service worker, sizes an installed app's window to the display, and shows the note that says how to install. | +| `sw.js` | Caches the app shell and runtime, then caches successful GET responses for offline reuse. The cache is named after `VERSION` in this file. | +| `style.css` | Shell and canvas presentation. | +| `icon-192.png`, `icon-512.png` | App icons. The 512 is also the maskable one. | +| `workers/` | Optional kit for running Python in Web Workers: `host.js`, `python_worker.js`, `audio_worklet.js`. See [Run your Python in Web Workers](../guides/run-in-a-worker.md). | +| `scripts/vendor_pyscript.sh` | Downloads the pinned offline PyScript release into generated `vendor/pyscript/`. Set `PYSCRIPT_VERSION` to override the pin for one run. | +| `vendor/pyscript/` | Generated and ignored by Git. Never hand-edit it. | diff --git a/sw.js b/sw.js index 50f30ed..e5f436b 100644 --- a/sw.js +++ b/sw.js @@ -2,7 +2,7 @@ // fetched, so a browser that has already visited keeps the old copies. Change // VERSION whenever you change a file: the next visit installs a worker with a // new cache and the old one is deleted. While you are editing, a hard reload -// skips the worker instead (see docs/pwa-guide.md, "Edits that don't show"). +// skips the worker instead (see docs/guides/make-it-installable.md, "Edits that don't show"). const VERSION = '2'; const CACHE_NAME = 'pyscript-template-' + VERSION; const SHELL = [