diff --git a/README.md b/README.md
index 7451e30d..9d9b73be 100644
--- a/README.md
+++ b/README.md
@@ -38,6 +38,20 @@ The system learns each environment locally using spiking neural networks that ad
RuView turns ordinary WiFi into a contactless sensor. A $9 ESP32 board reads the radio reflections off the people in a room, and a small pretrained model — published on Hugging Face at [`ruvnet/wifi-densepose-pretrained`](https://huggingface.co/ruvnet/wifi-densepose-pretrained) — tells you who's there, how they're breathing, and how their heart rate is trending. The model fits in 8 KB (4-bit quantized) and runs in microseconds on a Raspberry Pi. (The [v2 encoder](https://huggingface.co/ruvnet/wifi-densepose-pretrained) reports an honest, label-free held-out **temporal-triplet accuracy of 82.3%** — up from 66.4% raw; the older "100% presence" figure was measured on a single-class recording and has been retracted in favor of this.) No cameras, no wearables, no app on the user's phone.
+## Run `RuView` in Google Colab
+
+Experience `RuView` virtually using Google Colab. This notebook sets up and runs the `wifi-densepose-sensing-server` in a cloud environment.
+
+[](https://colab.research.google.com/github/ruvnet/RuView/blob/main/path/to/your/notebook.ipynb)
+
+### Quick Start:
+
+1. **Open the Colab Notebook** using the badge above.
+2. **Obtain an ngrok Auth Token** from [ngrok.com](https://dashboard.ngrok.com/get-started/your-authtoken) and paste it into `NGROK_AUTH_TOKEN` in Cell 0.
+3. **Run All Cells** (`Runtime` > `Run all`).
+4. After Cell 6 provides a "Public URL", copy the hostname (e.g., `example.ngrok-free.dev`) and update `NGROK_HOST` in Cell 5 with it. Re-run Cell 5 and subsequent cells.
+5. **Access the UI** via the ngrok public URL displayed in Cell 6.
+
### Built for low-power edge applications
[Edge modules](#edge-intelligence-adr-041) are small programs that run directly on the ESP32 sensor — no internet needed, no cloud fees, instant response.
diff --git a/assets/ruview-seed.png b/assets/ruview-seed.png
index ff51dcc5..1337f4a3 100644
Binary files a/assets/ruview-seed.png and b/assets/ruview-seed.png differ
diff --git a/assets/ruview-small-gemini.jpg b/assets/ruview-small-gemini.jpg
index b1f6e501..26896580 100644
Binary files a/assets/ruview-small-gemini.jpg and b/assets/ruview-small-gemini.jpg differ
diff --git a/assets/ruview-small.jpg b/assets/ruview-small.jpg
index 5655e0e7..ec4c29bd 100644
Binary files a/assets/ruview-small.jpg and b/assets/ruview-small.jpg differ
diff --git a/assets/screen.png b/assets/screen.png
index b9c70a66..a57e3a56 100644
Binary files a/assets/screen.png and b/assets/screen.png differ
diff --git a/assets/screenshot.png b/assets/screenshot.png
index 4e9cf5bb..5013f347 100644
Binary files a/assets/screenshot.png and b/assets/screenshot.png differ
diff --git a/assets/seed.png b/assets/seed.png
index 8e6ebc47..c7a7469c 100644
Binary files a/assets/seed.png and b/assets/seed.png differ
diff --git a/assets/v2-screen.png b/assets/v2-screen.png
index 0e0808b4..3634b18c 100644
Binary files a/assets/v2-screen.png and b/assets/v2-screen.png differ
diff --git a/colab_ruview_ngrok_demo.ipynb b/colab_ruview_ngrok_demo.ipynb
new file mode 100644
index 00000000..54c6c2f1
--- /dev/null
+++ b/colab_ruview_ngrok_demo.ipynb
@@ -0,0 +1,333 @@
+{
+ "nbformat": 4,
+ "nbformat_minor": 0,
+ "metadata": {
+ "colab": {
+ "provenance": [],
+ "authorship_tag": "ABX9TyM6ZfhRPbrd/iTT3jekChL3",
+ "include_colab_link": true
+ },
+ "kernelspec": {
+ "name": "python3",
+ "display_name": "Python 3"
+ },
+ "language_info": {
+ "name": "python"
+ }
+ },
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "view-in-github",
+ "colab_type": "text"
+ },
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "RlvccJ0kvDVB"
+ },
+ "outputs": [],
+ "source": [
+ "# === Cell 0: ngrok auth token ===\n",
+ "# To get your ngrok auth token:\n",
+ "# 1. Sign up/log in at https://ngrok.com/\n",
+ "# 2. Go to 'Your Authtoken' in the dashboard: https://dashboard.ngrok.com/get-started/your-authtoken\n",
+ "# 3. Copy your authtoken and paste it below.\n",
+ "NGROK_AUTH_TOKEN = \"YOUR_NGROK_AUTH_TOKEN_HERE\"\n",
+ "\n",
+ "if NGROK_AUTH_TOKEN == \"YOUR_NGROK_AUTH_TOKEN_HERE\":\n",
+ " print(\"⚠️ Paste your ngrok token into NGROK_AUTH_TOKEN, then re-run this cell.\")\n",
+ "else:\n",
+ " print(\"✅ ngrok token set (showing prefix only):\", NGROK_AUTH_TOKEN[:10] + \"...\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "# === Cell 1: install deps ===\n",
+ "!pip -q install pyngrok requests\n",
+ "\n",
+ "print(\"✅ Installed pyngrok + requests\")"
+ ],
+ "metadata": {
+ "id": "Bg0glm4oPUmd"
+ },
+ "execution_count": null,
+ "outputs": []
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "# === Cell 2: clone repo ===\n",
+ "import os, subprocess, textwrap, sys\n",
+ "\n",
+ "REPO_URL = \"https://github.com/ruvnet/RuView\"\n",
+ "REPO_DIR = \"RuView\"\n",
+ "\n",
+ "if not os.path.exists(REPO_DIR):\n",
+ " !git clone --depth 1 {REPO_URL} {REPO_DIR}\n",
+ "else:\n",
+ " print(\"✅ Repo already cloned\")\n",
+ "\n",
+ "print(\"📁 Repo dir:\", os.path.abspath(REPO_DIR))"
+ ],
+ "metadata": {
+ "id": "T4HLDmx-Pn7a"
+ },
+ "execution_count": null,
+ "outputs": []
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "# === Cell 3: find likely server entrypoints ===\n",
+ "import os, re, pathlib, json\n",
+ "\n",
+ "root = pathlib.Path(\"RuView\")\n",
+ "\n",
+ "candidates = []\n",
+ "\n",
+ "# Common patterns\n",
+ "patterns = [\n",
+ " (\"Cargo.toml\", r\"\\[package\\]\"),\n",
+ " (\"docker\", r\"Dockerfile\"),\n",
+ " (\"python-fastapi\", r\"FastAPI\\(\"),\n",
+ " (\"uvicorn\", r\"uvicorn\"),\n",
+ " (\"axum\", r\"axum\"),\n",
+ " (\"rocket\", r\"rocket::\"),\n",
+ "]\n",
+ "\n",
+ "# Scan a subset of files (avoid huge scan)\n",
+ "for p in root.rglob(\"*\"):\n",
+ " if p.is_dir():\n",
+ " continue\n",
+ " if p.suffix.lower() not in [\".md\", \".toml\", \".rs\", \".py\", \".yml\", \".yaml\", \".json\", \".sh\", \".ts\", \".js\"]:\n",
+ " continue\n",
+ " # Skip big files\n",
+ " try:\n",
+ " if p.stat().st_size > 2_000_000:\n",
+ " continue\n",
+ " txt = p.read_text(errors=\"ignore\")\n",
+ " except Exception:\n",
+ " continue\n",
+ "\n",
+ " hit = False\n",
+ " for tag, rx in patterns:\n",
+ " if re.search(rx, txt):\n",
+ " hit = True\n",
+ " break\n",
+ " if hit:\n",
+ " candidates.append(str(p))\n",
+ "\n",
+ "# Print a small curated list (top 60)\n",
+ "print(\"Found candidate files (showing up to 60):\")\n",
+ "for f in candidates[:60]:\n",
+ " print(\" -\", f)\n",
+ "\n",
+ "print(\"\\nNext: we will choose the correct server command based on what we find.\")"
+ ],
+ "metadata": {
+ "id": "tBx6uZ_oQd9q"
+ },
+ "execution_count": null,
+ "outputs": []
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "# === Cell 4: run cargo from the Rust workspace root (v2/) ===\n",
+ "\n",
+ "import os, shutil, subprocess\n",
+ "\n",
+ "# Ensure current process sees cargo in PATH (even if shell wasn't restarted)\n",
+ "if shutil.which(\"cargo\") is None:\n",
+ " # rustup wrote this file; sourcing it would normally happen in a shell\n",
+ " cargo_env = os.path.expanduser(\"~/.cargo/env\")\n",
+ " if os.path.exists(cargo_env):\n",
+ " # Minimal PATH fix for this Python process\n",
+ " os.environ[\"PATH\"] = os.path.expanduser(\"~/.cargo/bin\") + \":\" + os.environ.get(\"PATH\", \"\")\n",
+ "print(\"cargo:\", shutil.which(\"cargo\"))\n",
+ "\n",
+ "# Move into the Rust workspace directory\n",
+ "%cd /content/RuView/v2\n",
+ "\n",
+ "# Confirm Cargo.toml exists here\n",
+ "!ls -la | head -n 50\n",
+ "!test -f Cargo.toml && echo \"✅ Found v2/Cargo.toml\" || (echo \"❌ Cargo.toml still missing\" && exit 1)\n",
+ "\n",
+ "print(\"\\n--- Checking sensing-server help ---\")\n",
+ "!cargo run -q -p wifi-densepose-sensing-server -- --help | head -n 120"
+ ],
+ "metadata": {
+ "collapsed": true,
+ "id": "OJNZLiILXLTK"
+ },
+ "execution_count": null,
+ "outputs": []
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "# === Cell 5: hardcode SENSING_ALLOWED_HOSTS for ngrok ===\n",
+ "\n",
+ "import subprocess, time, socket, threading, shlex, os\n",
+ "\n",
+ "HTTP_PORT = 3000\n",
+ "BIND_ADDR = \"0.0.0.0\"\n",
+ "UI_PATH = \"../ui\"\n",
+ "\n",
+ "# Put your ngrok hostname here (NO https://, just host).\n",
+ "# After running Cell 6 with your NGROK_AUTH_TOKEN, you will see a public URL.\n",
+ "# For example, if the public URL is 'https://rewire-confirm-humongous.ngrok-free.dev',\n",
+ "# then your NGROK_HOST should be 'rewire-confirm-humongous.ngrok-free.dev'.\n",
+ "NGROK_HOST = \"YOUR_NGROK_HOST_HERE\"\n",
+ "\n",
+ "def is_port_open(port, host=\"127.0.0.1\"):\n",
+ " s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n",
+ " try:\n",
+ " s.settimeout(0.5)\n",
+ " return s.connect_ex((host, port)) == 0\n",
+ " finally:\n",
+ " s.close()\n",
+ "\n",
+ "# Hardcode all common Host header variants that may reach the server via ngrok/proxies\n",
+ "SENSING_ALLOWED_HOSTS = \",\".join([\n",
+ " NGROK_HOST,\n",
+ " f\"{NGROK_HOST}:443\",\n",
+ " f\"{NGROK_HOST}:80\",\n",
+ " f\"{NGROK_HOST}:{HTTP_PORT}\",\n",
+ " \"localhost\",\n",
+ " f\"localhost:{HTTP_PORT}\",\n",
+ " \"127.0.0.1\",\n",
+ " f\"127.0.0.1:{HTTP_PORT}\",\n",
+ "])\n",
+ "\n",
+ "env = os.environ.copy()\n",
+ "env[\"SENSING_ALLOWED_HOSTS\"] = SENSING_ALLOWED_HOSTS\n",
+ "\n",
+ "cmd = [\n",
+ " \"cargo\", \"run\", \"-q\", \"-p\", \"wifi-densepose-sensing-server\", \"--\",\n",
+ " \"--bind-addr\", BIND_ADDR,\n",
+ " \"--http-port\", str(HTTP_PORT),\n",
+ " \"--ui-path\", UI_PATH,\n",
+ " \"--source\", \"simulate\",\n",
+ "]\n",
+ "\n",
+ "print(\"Starting sensing-server:\\n \", \" \".join(shlex.quote(x) for x in cmd))\n",
+ "print(\"SENSING_ALLOWED_HOSTS =\", env[\"SENSING_ALLOWED_HOSTS\"])\n",
+ "\n",
+ "server_proc = subprocess.Popen(\n",
+ " cmd,\n",
+ " stdout=subprocess.PIPE,\n",
+ " stderr=subprocess.STDOUT,\n",
+ " text=True,\n",
+ " bufsize=1,\n",
+ " env=env\n",
+ ")\n",
+ "\n",
+ "# Stream logs\n",
+ "log_lines = []\n",
+ "def pump_logs():\n",
+ " for line in server_proc.stdout:\n",
+ " line = line.rstrip()\n",
+ " log_lines.append(line)\n",
+ " print(line)\n",
+ "\n",
+ "t = threading.Thread(target=pump_logs, daemon=True)\n",
+ "t.start()\n",
+ "\n",
+ "print(f\"\\nWaiting for HTTP listener on 127.0.0.1:{HTTP_PORT} ...\")\n",
+ "for i in range(60):\n",
+ " if is_port_open(HTTP_PORT, \"127.0.0.1\"):\n",
+ " print(f\"\\n✅ Server is listening at http://127.0.0.1:{HTTP_PORT}\")\n",
+ " break\n",
+ " if i % 10 == 0:\n",
+ " print(f\" ... {i}/60 seconds\")\n",
+ " time.sleep(1)"
+ ],
+ "metadata": {
+ "id": "-qGg5k0ZXNrW"
+ },
+ "execution_count": null,
+ "outputs": []
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "# === Cell 6: ngrok tunnel ===\n",
+ "from pyngrok import ngrok\n",
+ "\n",
+ "if NGROK_AUTH_TOKEN != \"YOUR_NGROK_AUTH_TOKEN_HERE\":\n",
+ " ngrok.set_auth_token(NGROK_AUTH_TOKEN)\n",
+ " public_url = ngrok.connect(3000, \"http\")\n",
+ " print(\"✅ Public URL:\", public_url)\n",
+ "else:\n",
+ " print(\"⚠️ No token set; skipping ngrok\")"
+ ],
+ "metadata": {
+ "id": "dmzklhVuXPvc"
+ },
+ "execution_count": null,
+ "outputs": []
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "# === Cell 7: test the correct endpoints for wifi-densepose-sensing-server ===\n",
+ "import requests, json\n",
+ "\n",
+ "base = \"http://127.0.0.1:3000\"\n",
+ "\n",
+ "paths = [\n",
+ " \"/health\",\n",
+ " \"/ui/index.html\",\n",
+ "\n",
+ " # Pose + zones\n",
+ " \"/api/v1/pose/current\",\n",
+ " \"/api/v1/pose/stats\",\n",
+ " \"/api/v1/pose/zones/summary\",\n",
+ "\n",
+ " # Vital signs\n",
+ " \"/api/v1/vital-signs\",\n",
+ " \"/api/v1/edge-vitals\",\n",
+ "\n",
+ " # Stream + introspection\n",
+ " \"/api/v1/stream/status\",\n",
+ " \"/api/v1/introspection/snapshot\",\n",
+ "\n",
+ " # Model info (may be empty if no model loaded)\n",
+ " \"/api/v1/model/info\",\n",
+ " \"/api/v1/models\",\n",
+ " \"/api/v1/models/active\",\n",
+ "]\n",
+ "\n",
+ "for path in paths:\n",
+ " url = base + path\n",
+ " try:\n",
+ " r = requests.get(url, timeout=8)\n",
+ " print(f\"{path} -> {r.status_code}\")\n",
+ "\n",
+ " ctype = r.headers.get(\"content-type\", \"\")\n",
+ " if \"application/json\" in ctype:\n",
+ " print(\" \", json.dumps(r.json(), indent=2)[:1200])\n",
+ " else:\n",
+ " # show a small snippet for HTML/text\n",
+ " print(\" \", r.text[:200].replace(\"\\n\", \" \") + (\"...\" if len(r.text) > 200 else \"\"))\n",
+ " except Exception as e:\n",
+ " print(f\"{path} -> ERROR: {type(e).__name__}: {str(e)[:200]}\")\n",
+ " print()"
+ ],
+ "metadata": {
+ "id": "xAMHOUOiXR_D"
+ },
+ "execution_count": null,
+ "outputs": []
+ }
+ ]
+}
\ No newline at end of file
diff --git a/dashboard/public/icon-192.svg b/dashboard/public/icon-192.svg
index a378624b..d4d02698 100644
--- a/dashboard/public/icon-192.svg
+++ b/dashboard/public/icon-192.svg
@@ -1,4 +1 @@
-
+
\ No newline at end of file
diff --git a/dashboard/public/icon-512.svg b/dashboard/public/icon-512.svg
index 67372c10..9168f22f 100644
--- a/dashboard/public/icon-512.svg
+++ b/dashboard/public/icon-512.svg
@@ -1,10 +1 @@
-
+
\ No newline at end of file
diff --git a/docs/archtocode-visual-overview/advanced-architecture.png b/docs/archtocode-visual-overview/advanced-architecture.png
index c4f47cbf..5a3421eb 100644
Binary files a/docs/archtocode-visual-overview/advanced-architecture.png and b/docs/archtocode-visual-overview/advanced-architecture.png differ
diff --git a/docs/archtocode-visual-overview/error-handling-flow.png b/docs/archtocode-visual-overview/error-handling-flow.png
index 6289c31d..670c576a 100644
Binary files a/docs/archtocode-visual-overview/error-handling-flow.png and b/docs/archtocode-visual-overview/error-handling-flow.png differ
diff --git a/docs/archtocode-visual-overview/frontent-architecture.png b/docs/archtocode-visual-overview/frontent-architecture.png
index 6e9f5f95..df9a4e74 100644
Binary files a/docs/archtocode-visual-overview/frontent-architecture.png and b/docs/archtocode-visual-overview/frontent-architecture.png differ
diff --git a/docs/archtocode-visual-overview/hight-level-flow-architecture.png b/docs/archtocode-visual-overview/hight-level-flow-architecture.png
index 59872d19..09eefd4d 100644
Binary files a/docs/archtocode-visual-overview/hight-level-flow-architecture.png and b/docs/archtocode-visual-overview/hight-level-flow-architecture.png differ
diff --git a/docs/archtocode-visual-overview/project-timeline.png b/docs/archtocode-visual-overview/project-timeline.png
index 48cb5399..5d4ba2d1 100644
Binary files a/docs/archtocode-visual-overview/project-timeline.png and b/docs/archtocode-visual-overview/project-timeline.png differ
diff --git a/docs/archtocode-visual-overview/state-decision-flow.png b/docs/archtocode-visual-overview/state-decision-flow.png
index e7fea6d9..3142ad56 100644
Binary files a/docs/archtocode-visual-overview/state-decision-flow.png and b/docs/archtocode-visual-overview/state-decision-flow.png differ
diff --git a/examples/three.js/screenshots/01-helpers.png b/examples/three.js/screenshots/01-helpers.png
index 4755e996..07c44d42 100644
Binary files a/examples/three.js/screenshots/01-helpers.png and b/examples/three.js/screenshots/01-helpers.png differ
diff --git a/examples/three.js/screenshots/02-cinematic.png b/examples/three.js/screenshots/02-cinematic.png
index c4737196..6fcc823b 100644
Binary files a/examples/three.js/screenshots/02-cinematic.png and b/examples/three.js/screenshots/02-cinematic.png differ
diff --git a/examples/three.js/screenshots/03-skinned.png b/examples/three.js/screenshots/03-skinned.png
index 713aa593..22aea383 100644
Binary files a/examples/three.js/screenshots/03-skinned.png and b/examples/three.js/screenshots/03-skinned.png differ
diff --git a/examples/three.js/screenshots/04-skinned-fbx.png b/examples/three.js/screenshots/04-skinned-fbx.png
index b747f6dc..395ef394 100644
Binary files a/examples/three.js/screenshots/04-skinned-fbx.png and b/examples/three.js/screenshots/04-skinned-fbx.png differ
diff --git a/examples/three.js/screenshots/05-skinned-realtime.png b/examples/three.js/screenshots/05-skinned-realtime.png
index 58268eca..4b635e70 100644
Binary files a/examples/three.js/screenshots/05-skinned-realtime.png and b/examples/three.js/screenshots/05-skinned-realtime.png differ
diff --git a/references/densepose_performance_chart.png b/references/densepose_performance_chart.png
index a9accde3..85811e2f 100644
Binary files a/references/densepose_performance_chart.png and b/references/densepose_performance_chart.png differ
diff --git a/references/generated_image.png b/references/generated_image.png
index fbfa0693..a889b415 100644
Binary files a/references/generated_image.png and b/references/generated_image.png differ
diff --git a/references/generated_image_1.png b/references/generated_image_1.png
index a8e4d019..d098409c 100644
Binary files a/references/generated_image_1.png and b/references/generated_image_1.png differ
diff --git a/references/wifi-densepose-arch.png b/references/wifi-densepose-arch.png
index fbfa0693..a889b415 100644
Binary files a/references/wifi-densepose-arch.png and b/references/wifi-densepose-arch.png differ
diff --git a/ui/mobile/assets/android-icon-background.png b/ui/mobile/assets/android-icon-background.png
index 5ffefc5b..c5d23a1a 100644
Binary files a/ui/mobile/assets/android-icon-background.png and b/ui/mobile/assets/android-icon-background.png differ
diff --git a/ui/mobile/assets/android-icon-foreground.png b/ui/mobile/assets/android-icon-foreground.png
index 3a9e5016..a20fa889 100644
Binary files a/ui/mobile/assets/android-icon-foreground.png and b/ui/mobile/assets/android-icon-foreground.png differ
diff --git a/ui/mobile/assets/android-icon-monochrome.png b/ui/mobile/assets/android-icon-monochrome.png
index 77484ebd..93a4c73a 100644
Binary files a/ui/mobile/assets/android-icon-monochrome.png and b/ui/mobile/assets/android-icon-monochrome.png differ
diff --git a/ui/mobile/assets/favicon.png b/ui/mobile/assets/favicon.png
index 408bd746..9e6d3911 100644
Binary files a/ui/mobile/assets/favicon.png and b/ui/mobile/assets/favicon.png differ
diff --git a/v2/crates/wifi-densepose-desktop/icons/128x128.png b/v2/crates/wifi-densepose-desktop/icons/128x128.png
index 6ecba26c..fd58c780 100644
Binary files a/v2/crates/wifi-densepose-desktop/icons/128x128.png and b/v2/crates/wifi-densepose-desktop/icons/128x128.png differ
diff --git a/v2/crates/wifi-densepose-desktop/icons/128x128@2x.png b/v2/crates/wifi-densepose-desktop/icons/128x128@2x.png
index ccdfb4a8..4382ebca 100644
Binary files a/v2/crates/wifi-densepose-desktop/icons/128x128@2x.png and b/v2/crates/wifi-densepose-desktop/icons/128x128@2x.png differ