Skip to content
Merged
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
10 changes: 5 additions & 5 deletions docs/beginning-pyscript.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ module, and a `<link>` to some PyScript specific CSS, in the document's
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>🦜 Polyglot - Piratical PyScript</title>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.1.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.1.1/core.js"></script>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.2.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.2.1/core.js"></script>
</head>
<body>

Expand Down Expand Up @@ -165,8 +165,8 @@ In the end, our HTML should look like this:
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>🦜 Polyglot - Piratical PyScript</title>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.1.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.1.1/core.js"></script>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.2.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.2.1/core.js"></script>
</head>
<body>
<h1>Polyglot 🦜 💬 🇬🇧 ➡️ 🏴‍☠️</h1>
Expand Down Expand Up @@ -308,7 +308,7 @@ To run PyScript offline, without the need of a CDN or internet connection, read
the [offline guide](user-guide/offline.md) section of the user guide.

We also provide an `offline.zip` file with
[each release](https://pyscript.net/releases/2026.1.1/). This file contains
[each release](https://pyscript.net/releases/2026.2.1/). This file contains
everything you need for an offline version of PyScript: PyScript itself,
versions of Pyodide and MicroPython, and an index.html page from which you
could create your offline-first PyScript work.
Expand Down
4 changes: 2 additions & 2 deletions docs/example-apps/bouncing-ball/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>PyGame-CE Bouncing Ball</title>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.1.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.1.1/core.js"></script>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.2.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.2.1/core.js"></script>
<style>
body {
font-family: system-ui, sans-serif;
Expand Down
4 changes: 2 additions & 2 deletions docs/example-apps/colour-picker/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Interactive Colour Picker</title>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.1.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.1.1/core.js"></script>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.2.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.2.1/core.js"></script>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
Expand Down
4 changes: 2 additions & 2 deletions docs/example-apps/display-demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Display Demo</title>
<link rel="stylesheet"
href="https://pyscript.net/releases/2026.1.1/core.css">
href="https://pyscript.net/releases/2026.2.1/core.css">
<script type="module"
src="https://pyscript.net/releases/2026.1.1/core.js"></script>
src="https://pyscript.net/releases/2026.2.1/core.js"></script>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
Expand Down
4 changes: 2 additions & 2 deletions docs/example-apps/note-taker/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Note Taker</title>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.1.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.1.1/core.js"></script>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.2.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.2.1/core.js"></script>
<style>
body {
font-family: system-ui, sans-serif;
Expand Down
4 changes: 2 additions & 2 deletions docs/example-apps/photobooth/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Photobooth</title>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.1.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.1.1/core.js"></script>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.2.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.2.1/core.js"></script>
<style>
body {
font-family: system-ui, sans-serif;
Expand Down
4 changes: 2 additions & 2 deletions docs/example-apps/pirate-translator/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>🦜 Polyglot - Piratical PyScript</title>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.1.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.1.1/core.js"></script>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.2.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.2.1/core.js"></script>
</head>
<body>
<h1>Polyglot 🦜 💬 🇬🇧 ➡️ 🏴‍☠️</h1>
Expand Down
4 changes: 2 additions & 2 deletions docs/example-apps/prime-worker/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Prime Numbers with Workers</title>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.1.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.1.1/core.js"></script>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.2.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.2.1/core.js"></script>
<style>
body {
font-family: system-ui, sans-serif;
Expand Down
4 changes: 2 additions & 2 deletions docs/example-apps/task-board-ffi/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Task Board - FFI</title>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.1.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.1.1/core.js"></script>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.2.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.2.1/core.js"></script>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
Expand Down
4 changes: 2 additions & 2 deletions docs/example-apps/task-board-web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Task Board - pyscript.web</title>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.1.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.1.1/core.js"></script>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.2.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.2.1/core.js"></script>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
Expand Down
169 changes: 140 additions & 29 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,41 +58,36 @@ This is the most common error new PyScript users face:

#### When

This error occurs when code running in a worker tries to access `window`
or `document` objects that exist on the main thread.
This error occurs when code running in a worker tries to access
`window` or `document` objects from the main thread.

The error indicates either **your web server is incorrectly configured**
or **a `service-worker` attribute is missing from your script element**.
It indicates one of three situations:

Specifically, one of three situations applies:
1. **Server misconfiguration:** Your script has a `worker` attribute and
accesses `window` or `document`, but your web server isn't configured to
enable SharedArrayBuffer/Atomics.

Your web server configuration prevents the browser from enabling Atomics
(a technology for cross-thread communication). When your script element
has a `worker` attribute and your Python code uses `window` or
`document` objects that exist on the main thread, this browser
limitation causes failure unless you reconfigure your server.
2. **Missing service-worker attribute:** You're using
`<script type="py-editor">` (which always runs in a worker) without
providing a `service-worker` attribute for fallback synchronous operations.

You're using `<script type="py-editor">` (which always runs in a worker)
without providing a fallback via a `service-worker` attribute on that
element.
3. **PyWorker without fallback:** You've created a `PyWorker` or `MPWorker`
instance without providing a `service_worker` fallback (see:
[this API class](./api/context.md/#pyscript.context.PyWorker)).

You've explicitly created a `PyWorker` or `MPWorker` instance somewhere
in your code without providing a `service_worker` fallback.

The [workers guide](./user-guide/workers.md) documents all these cases
The [workers guide](./user-guide/workers.md) documents all these use cases
with code examples and solutions.

#### Why

For `document.getElementById('some-id').value` to work in a worker,
JavaScript requires two primitives:

[SharedArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer)
allows multiple threads to read and write shared memory.
Workers often require two browser based features to access main thread objects
like `window` and `document`.

[Atomics](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics)
provides `wait(sab, index)` and `notify(sab, index)` to coordinate
threads, where `sab` is a SharedArrayBuffer.
1. [SharedArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer)
allows multiple threads to read and write shared memory.
2. [Atomics](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics)
provides `wait(sab, index)` and `notify(sab, index)` to coordinate
threads, where `sab` is a SharedArrayBuffer.

Whilst a worker waits for a main thread operation, it doesn't consume
CPU. It idles until the referenced buffer index changes, effectively
Expand All @@ -105,8 +100,124 @@ responsive during heavy computation.

Unfortunately, we cannot patch or work around these primitives - they're
defined by web standards. However, various solutions exist for working
within these limitations. The [workers guide](./user-guide/workers.md)
explains how.
within these limitations.

The easiest fix is to ensure your webserver is correctly configured to
serve responses with the following headers:

```
Access-Control-Allow-Origin: *
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Resource-Policy: cross-origin
```

If you are unable to reconfigure your webserver (perhaps, for example,
you're using a third party for hosting), you have two options:

**Option 1:** `mini-coi`

The `mini-coi` project ensures a browser's
[complicated Cross Origin Isolation (COI) settings](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements)
"just work" for web workers. This is especially useful when you have no
control over the HTTP headers returned by the server.

For performance reasons, this is the preferred option so Atomics works at
native speed.

The simplest way to use mini-coi is to copy the
[`mini-coi.js`](https://raw.githubusercontent.com/WebReflection/mini-coi/main/mini-coi.js)
file to the root of your website (i.e. `/`), and reference it as the first
child tag in the `<head>` of your HTML documents:

```html
<html>
<head>
<script src="/mini-coi.js"></script>
<!-- etc -->
</head>
<!-- etc -->
</html>
```

**Option 2:** `service-worker` attribute

This allows you to slot in a custom
[service worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API)
to handle requirements for synchronous operations.

Each `<script type="m/py">` or `<m/py-script>` may optionally have a
`service-worker` attribute pointing to a locally served file (the same way
`mini-coi.js` needs to be served).

This file needs to orchestrate _coincident POST_ requests so that:

* You can copy and paste
[the coincident Service Worker](https://cdn.jsdelivr.net/npm/coincident/dist/sw.js)
into your local project and point at that via the `service-worker`
attribute. This will not change the original behavior of your project, it
will not interfere with the default or pre-defined headers your application
uses already but it will **fallback to a (slower but working) synchronous
operation** that allows both `window` and `document` access in your worker
logic.
* You can import
[coincident listeners](https://github.com/WebReflection/coincident/blob/main/src/sabayon/listeners.js)
in your project and at least add the `fetch` one before your listeners. It
will automatically stop propagation when a request is meant to be handled
so that the rest of your logic will not be affected or change by any mean.

```html
<html>
<head>
<!-- PyScript link and script -->
</head>
<body>
<script type="py" service-worker="./sw.js" worker>
from pyscript import window, document

document.body.append("Hello PyScript!")
</script>
</body>
</html>
```

!!! warning

Using _coincident_ as the fallback for synchronous operations via Atomics
should be **the last solution to consider**. It is inevitably slower than
using native Atomics.

If you must use `service-worker` attribute, always reduce the amount of
synchronous operations by caching references from the _main_ thread.

```python
# ❌ THIS IS UNNECESSARILY SLOWER
from pyscript import document

# add a data-test="not ideal attribute"
document.body.dataset.test = "not ideal"
# read a data-test attribute
print(document.body.dataset.test)

# - - - - - - - - - - - - - - - - - - - - -

# ✔️ THIS IS FINE
from pyscript import document

# if needed elsewhere, reach it once
body = document.body
dataset = body.dataset

# add a data-test="not ideal attribute"
dataset.test = "not ideal"
# read a data-test attribute
print(dataset.test)
```

In latter example the number of operations has been reduced from six to
just four. The rule of thumb is: _if you ever need a DOM reference more
than once, cache it_.


### Borrowed proxy

Expand Down Expand Up @@ -430,7 +541,7 @@ versions or use `latest`:

```html
<!-- Specific version (recommended for production). -->
<script type="module" src="https://pyscript.net/releases/2026.1.1/core.js"></script>
<script type="module" src="https://pyscript.net/releases/2026.2.1/core.js"></script>

<!-- Latest version (useful for development). -->
<script type="module" src="https://pyscript.net/latest/core.js"></script>
Expand Down Expand Up @@ -461,7 +572,7 @@ You can create workers programmatically from JavaScript:

```html
<script type="module">
import { PyWorker } from "https://pyscript.net/releases/2026.1.1/core.js";
import { PyWorker } from "https://pyscript.net/releases/2026.2.1/core.js";

const worker = new PyWorker("./worker.py", {type: "pyodide"});

Expand Down
4 changes: 2 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
**Step 1:** Add these two lines to the `<head>` of your HTML document:

```html
<link rel="stylesheet" href="https://pyscript.net/releases/2026.1.1/core.css" />
<script type="module" src="https://pyscript.net/releases/2026.1.1/core.js"></script>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.2.1/core.css" />
<script type="module" src="https://pyscript.net/releases/2026.2.1/core.js"></script>
```

**Step 2:** Start PyScript with a `<script>` tag in the `<body>` of your HTML document:
Expand Down
4 changes: 2 additions & 2 deletions docs/user-guide/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -667,8 +667,8 @@ Here's a complete example showing common configuration options:
<head>
<meta charset="utf-8" />
<title>My PyScript App</title>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.1.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.1.1/core.js"></script>
<link rel="stylesheet" href="https://pyscript.net/releases/2026.2.1/core.css">
<script type="module" src="https://pyscript.net/releases/2026.2.1/core.js"></script>
</head>
<body>
<h1>Data Analysis</h1>
Expand Down
4 changes: 2 additions & 2 deletions docs/user-guide/from_javascript.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ serialised to formats JavaScript can understand.
JavaScript code imports the storage module from PyScript core:

```javascript title="Access storage in JavaScript."
import storage from 'https://pyscript.net/releases/2026.1.1/storage.js';
import storage from 'https://pyscript.net/releases/2026.2.1/storage.js';


const my_store = await storage(name="shared");
Expand Down Expand Up @@ -81,7 +81,7 @@ use Python from pure JavaScript without writing PyScript tags.
Import the `donkey` function and create a worker with it:

```javascript title="Call for the PyScript donkey."
import { donkey } from 'https://pyscript.net/releases/2026.1.1/core.js';
import { donkey } from 'https://pyscript.net/releases/2026.2.1/core.js';

const py_donkey = await donkey({
type: 'mpy', // Use MicroPython ('py' for Pyodide).
Expand Down
2 changes: 1 addition & 1 deletion docs/user-guide/offline.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ libraries, the package files must also be available offline.
## Shortcut

Helpfully, since the end of 2025, all
[releases of PyScript](https://pyscript.net/releases/2026.1.1/)
[releases of PyScript](https://pyscript.net/releases/2026.2.1/)
have an associated `offline`
zip file containing everything you need. Just download it, unpack it and
start to modify the content of the `index.html` found therein to your needs.
Expand Down
Loading