diff --git a/examples/raytrace-parallel/.gitignore b/examples/raytrace-parallel/.gitignore
deleted file mode 100644
index 8b5555eb0cf..00000000000
--- a/examples/raytrace-parallel/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-raytrace_parallel.js
-raytrace_parallel_bg.wasm
diff --git a/examples/raytrace-parallel/README.md b/examples/raytrace-parallel/README.md
index 296e9aa8fbe..a09c42bbf2a 100644
--- a/examples/raytrace-parallel/README.md
+++ b/examples/raytrace-parallel/README.md
@@ -9,9 +9,7 @@ online][compiled]
You can build the example locally with:
```
-$ ./run.sh
+$ python3 run.py
```
-(or running the commands on Windows manually)
-
and then visiting http://localhost:8080 in a browser should run the example!
diff --git a/examples/raytrace-parallel/build.py b/examples/raytrace-parallel/build.py
new file mode 100755
index 00000000000..0e14f490711
--- /dev/null
+++ b/examples/raytrace-parallel/build.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+import os
+import subprocess
+
+root_dir = os.path.dirname(__file__)
+
+# A couple of steps are necessary to get this build working which makes it slightly
+# nonstandard compared to most other builds.
+#
+# * First, the Rust standard library needs to be recompiled with atomics
+# enabled. to do that we use Cargo's unstable `-Zbuild-std` feature.
+#
+# * Next we need to compile everything with the `atomics` and `bulk-memory`
+# features enabled, ensuring that LLVM will generate atomic instructions,
+# shared memory, passive segments, etc.
+
+os.environ.update(
+ {"RUSTFLAGS": "-C target-feature=+atomics,+bulk-memory,+mutable-globals"}
+)
+
+subprocess.run(
+ [
+ "cargo",
+ "build",
+ "--target",
+ "wasm32-unknown-unknown",
+ "--release",
+ "-Zbuild-std=std,panic_abort",
+ ],
+ cwd=root_dir,
+).check_returncode()
+
+# Note the usage of `--target no-modules` here which is required for passing
+# the memory import to each wasm module.
+subprocess.run(
+ [
+ "cargo",
+ "run",
+ "-p",
+ "wasm-bindgen-cli",
+ "--",
+ os.path.join(
+ root_dir,
+ "..",
+ "..",
+ "target",
+ "wasm32-unknown-unknown",
+ "release",
+ "raytrace_parallel.wasm",
+ ),
+ "--out-dir",
+ os.path.join(root_dir, "pkg"),
+ "--target",
+ "no-modules",
+ ],
+ cwd=root_dir,
+).check_returncode()
diff --git a/examples/raytrace-parallel/build.sh b/examples/raytrace-parallel/build.sh
index f10dcf29dfb..09786f553ce 100755
--- a/examples/raytrace-parallel/build.sh
+++ b/examples/raytrace-parallel/build.sh
@@ -2,22 +2,4 @@
set -ex
-# A couple of steps are necessary to get this build working which makes it slightly
-# nonstandard compared to most other builds.
-#
-# * First, the Rust standard library needs to be recompiled with atomics
-# enabled. to do that we use Cargo's unstable `-Zbuild-std` feature.
-#
-# * Next we need to compile everything with the `atomics` and `bulk-memory`
-# features enabled, ensuring that LLVM will generate atomic instructions,
-# shared memory, passive segments, etc.
-
-RUSTFLAGS='-C target-feature=+atomics,+bulk-memory,+mutable-globals' \
- cargo build --target wasm32-unknown-unknown --release -Z build-std=std,panic_abort
-
-# Note the usage of `--target no-modules` here which is required for passing
-# the memory import to each wasm module.
-cargo run -p wasm-bindgen-cli -- \
- ../../target/wasm32-unknown-unknown/release/raytrace_parallel.wasm \
- --out-dir . \
- --target no-modules
+python3 build.py
diff --git a/examples/raytrace-parallel/index.html b/examples/raytrace-parallel/index.html
index bc9cae70616..2feedce4b00 100644
--- a/examples/raytrace-parallel/index.html
+++ b/examples/raytrace-parallel/index.html
@@ -219,7 +219,7 @@
document.getElementById('render').disabled = true;
document.getElementById('concurrency').disabled = true;
-
+