This is browser version of Path of Building.
- Run the PoB in your browser, that's all.
- You can select the version of the PoB to run.
- Saved builds are stored in the browser's local storage.
- The
Cloudfolder appears when you are logged into the site. Builds saved there are stored in the cloud and can be accessed from anywhere.
- The
- You can load a build by specifying a hash in the URL.
- Network access is through our CORS proxy, so all users have the same source IP. This will likely cause rate limiting.
- For security reasons, requests containing the POESESSID cookie will be unconditionally rejected. Do not enter POESESSID in the PoB of this site.
- We will not make any changes to the original PoB. This is because a lot of effort has been put into the PoB itself and
we want the community to focus on developing the offline version.
- However, it does make changes in behavior that are possible without changing the code.
This repository includes a submodule in vendor/lua. To include the
submodule when cloning the repository, use the --recurse-submodules flag:
git clone --recurse-submodules <repository-url>If you omitted the flag, you can use the following commands to clone the submodule:
git submodule init
git submodule updatemise run setupThis installs the pinned tools and Deno-managed dependencies, initializes the submodules, and installs the repository hooks.
Before running the development server, you need to pack the upstream PoB assets into a structure that the driver can use.
mise run pack --game poe2 --tag v0.8.0Set up a development server for the PoB web driver alone. Vite selects an available port and reports the URL.
mise run driver:dev --game poe2 --version v0.8.0Set up a web application development server. You need to build the driver first. Vite, the local Cloudflare Pages server, and its inspector select available ports, with the latter two forwarded to the frontend automatically.
mise run web:devExpose the web development server through a temporary Free Pinggy HTTPS URL:
mise run web:dev:publicOpen the HTTPS URL printed by Pinggy in iPhone Safari. The URL changes each time the task starts and is publicly
accessible without authentication, so do not put private build codes or credentials in it. Runtime diagnostics are
streamed as JSON lines to the development server's standard error; filter a session by its runId. Press Ctrl+C to stop
both the tunnel and the development server. Pass --pob-cool-asset to use the remote packed assets, as with web:dev.
If the workspace Playwright browser is not installed, prepare it in this trusted repository:
mise run setup
mise run visual:setupInvoke $investigate-canvas-ui from Codex to investigate the Canvas/WebGL interface with Playwright MCP Vision Mode.
The skill reuses a suitable running server when possible; otherwise it chooses driver:dev or web:dev for the target
behavior and uses the URL reported by the task. Development servers proxy remote asset.pob.cool data, so their ports
remain dynamic in remote-asset mode. The browser is stored in Playwright's standard OS cache and is not committed.
Headless mode is the default; start Codex with PLAYWRIGHT_MCP_HEADED=1 when a visible browser is needed for
investigation.
Use the fast check during development. Run the full test, including the WebAssembly and web builds, before completing build-related or cross-package changes:
mise run check
mise run testFor the adopted async runtime design, see ADR 0001: Use Atomics RPC without native Wasm SJLJ.
mise run check includes focused tests for driver keyboard state, Canvas transforms, and draw-command interpretation.
For a local runtime check against the current PoE 1, PoE 2, and Last Epoch heads from version.json, run:
mise run visual:setup
mise run test:e2e:driver
mise run test:e2e:webThe E2E tasks pack their required upstream releases locally and reuse those assets until the version or packer inputs
change. The driver runtime suite starts each head in Chromium and Firefox and checks item database loading, WebAssembly
startup, WebGL2 rendering, frame statistics, clipboard round trips, and the DOM zoom control. The web runtime suite
checks the critical path from the landing page through version loading and routing to a rendered driver session and web
toolbar control. Browser tests, development tasks, and MCP visual investigation select an available development-server
port and use the URL reported by Vite, so they can run alongside one another. To run only one game's current head, pass
--game; add --version only for a release-specific compatibility check:
mise run test:e2e:driver --game poe2
mise run test:e2e:driver --game poe2 --version <version>The full browser suites are intentionally kept out of the fast/full checks and pull-request CI. Run
mise run benchmark:driver to install its browser runtimes and collect five steady-state PoE 1 frame medians in both
Chromium and Firefox.
To verify the complete Wasm symbolication path without deploying, set SENTRY_LIVE_AUTH_TOKEN and SENTRY_LIVE_DSN,
then run mise run test:sentry:live. These test-only variables are separate from deployment credentials. The task
uploads the local Wasm debug file, sends intentional traps from Chromium and Firefox, and waits for both events to
resolve to the test functions in driver.c. The token requires org:ci and project:read; SENTRY_LIVE_ORG and
SENTRY_LIVE_PROJECT override the default project.
If you are the owner of pob.cool, you can set MISE_ENV=pob-cool to enable mise tasks.
The hourly upstream sync runs the targeted driver E2E after uploading each new release. Its result is stored in
version.json: tested releases are eligible to become the default version, while failed releases remain selectable
but do not replace the current default. Releases without a result predate this check and appear as Untested in the
version list.
graph TB
subgraph "Browser Environment"
subgraph "packages/web - React Web App"
WEB[React Router App]
AUTH[Auth0 Integration]
CLOUD[Cloud Storage]
end
subgraph "packages/driver - PoB Driver"
DRIVER[Driver Class]
CANVAS[Canvas Manager]
EVENT[Event Handler]
OVERLAY[React Overlays]
WEBGL[WebGL Renderer]
end
subgraph "WebAssembly Runtime"
WASM[Lua 5.2 Interpreter]
CBRIDGE[C Bridge Module]
POBCODE[Original PoB Lua Code]
end
subgraph "Asset Management"
PACKER[packages/packer]
ASSETS[Packed Assets]
CDN[asset.pob.cool CDN]
end
subgraph "Game Data"
GAMEDATA[packages/game]
POE1[Path of Exile 1]
POE2[Path of Exile 2]
LE[Last Epoch]
end
subgraph "External Services"
GITHUB[GitHub Repositories]
CORS[CORS Proxy]
PATHOFEXILE[Path of Exile API]
end
end
subgraph "Storage"
LOCAL[localStorage]
KV[Cloudflare KV]
end
%% Main data flow
WEB --> DRIVER
DRIVER --> WASM
WASM --> POBCODE
CBRIDGE --> DRIVER
DRIVER --> WEBGL
DRIVER --> CANVAS
DRIVER --> EVENT
DRIVER --> OVERLAY
%% Asset flow
PACKER --> ASSETS
ASSETS --> CDN
CDN --> DRIVER
GITHUB --> PACKER
%% Game data flow
GAMEDATA --> POE1
GAMEDATA --> POE2
GAMEDATA --> LE
GAMEDATA --> WEB
%% Storage flow
WEB --> LOCAL
AUTH --> CLOUD
CLOUD --> KV
%% Network flow
DRIVER --> CORS
CORS --> PATHOFEXILE
%% Styling
classDef webPackage fill:#e1f5fe
classDef driverPackage fill:#f3e5f5
classDef wasmPackage fill:#fff3e0
classDef assetPackage fill:#e8f5e8
classDef gamePackage fill:#fce4ec
classDef external fill:#f5f5f5
classDef storage fill:#fff8e1
class WEB,AUTH,CLOUD webPackage
class DRIVER,CANVAS,EVENT,OVERLAY,WEBGL driverPackage
class WASM,CBRIDGE,POBCODE wasmPackage
class PACKER,ASSETS,CDN assetPackage
class GAMEDATA,POE1,POE2,LE gamePackage
class GITHUB,CORS,PATHOFEXILE external
class LOCAL,KV storage
WebAssembly Runtime: The heart of pob-web is a custom Lua 5.2 interpreter compiled to WebAssembly using Emscripten. This allows the original Path of Building Lua codebase to run unmodified in the browser, maintaining 100% compatibility with the desktop version.
C Bridge Layer: A critical component written in C (packages/driver/src/c/) acts as a bridge between the Lua
runtime and the JavaScript driver. This includes:
- Custom implementations of PoB's graphics modules (equivalent to SimpleGraphic)
- File system abstraction using Emscripten's WASMFS
- Memory management and data marshaling between Lua and JavaScript contexts
JavaScript Driver: The packages/driver emulates the desktop PoB window environment using vanilla JavaScript and
WebGL:
- Canvas Management: Handles multiple rendering contexts and viewport management
- Event System: Translates browser events (mouse, keyboard, touch) to PoB-compatible input
- WebGL Renderer: Hardware-accelerated rendering pipeline that interprets PoB's drawing commands
- React Overlays: Mobile-optimized UI components (virtual keyboard, zoom controls) with scoped CSS
Upstream Integration: The packages/packer tool automatically processes releases from upstream PoB repositories:
- Downloads and extracts game assets, Lua scripts, and data files
- Compresses textures and optimizes assets for web delivery
- Generates manifest files for efficient loading
- Supports multiple games (PoE1, PoE2, Last Epoch) with version management
Content Delivery: Assets are served via CDN (asset.pob.cool) in production, with local filesystem fallback during development using Vite's virtual filesystem.
React Frontend: The packages/web provides the user-facing application:
- React Router v7 with server-side rendering capabilities
- Cloudflare Pages deployment with Workers functions for API endpoints
- Auth0 integration for user authentication and cloud storage
- Build management with localStorage and optional Cloudflare KV cloud sync
- Memory Management: Efficient data transfer between WebAssembly heap and JavaScript objects
- Graphics Translation: Converting PoB's immediate-mode graphics calls to WebGL draw commands
- File System Emulation: Providing a POSIX-like filesystem interface within browser constraints
- Mobile Adaptation: Touch-friendly overlays without modifying the original PoB interface
- Network Isolation: CORS proxy for external API calls while maintaining security
- Asset Optimization: Balancing file size with loading performance for large game databases
This architecture enables running complex desktop software in the browser while maintaining the principle of zero modifications to the original PoB codebase.