
Client web appSole developerDrawing 38 of 43
xPM Process
Library
I built a browser app for xPM, a construction project management company, that turns their library of 16,703 construction processes into a 3D graph and seven other views.
- StatusComplete, last commit March 31, 2026
- ClientxPM, a construction project management company
- Data16,703 processes under 7 stakeholder groups
- StackJavaScript, Three.js, D3, 3d-force-graph, G6, MediaPipe
- Runs asA static web app with a GitHub Pages deploy workflow
- Commits71, from March 2 to March 31, 2026
Sheet 02 of 09/Client
Who I built it for
xPM is a construction project management company working on an AI platform, and their work is organised around a library of processes. Each entry is a process, form or template that someone on a construction project works through, filed under a stakeholder group, a contractor, a stage and a sub-stage. The app was meant to live on xPM's site, and I took its colors and logo from there.
You sign in and land on a dashboard. The visualizations live on the Agent Map page, which loads the whole library and then asks which view you want.


Sheet 03 of 09/Data
From spreadsheets to one file
It started as an Excel checklist with tabs for the general contractor, the designer and the owner. I turned it into an Obsidian vault first, with one markdown note per process and the stages color coded in Obsidian's graph view. Then I wrote a web app to draw the vault as a 3D graph.
Next I imported more spreadsheets and moved everything into a folder tree eight levels deep, from stakeholder group down to the single process. The final export is a master CSV plus 59 files split by contractor, each as a CSV and an Excel sheet. The app loads one 25 MB JSON file built from that CSV, with all 16,703 processes in it.
When I cloned the repo onto a Windows machine, some of the paths were too long to check out. I renamed every file and folder in the vault so each name stayed under 250 characters.
In the app, the table shows that file flat, grouped by stage, or folded into a hierarchy with a process count on every group.




Sheet 04 of 09/Views
Eight ways to see the same library
The picker has eight views. There's the 3D graph, a table, a layered network, a sunburst, a treemap, a Sankey diagram, a globe and a 2D tree. They all read the same filters, so a stakeholder chip or a stage picked in the sidebar narrows whichever view is open. There's a light theme as well as the dark one.
The sunburst, the treemap and the tree start near the top of the hierarchy and open further when you click. A slice zooms the sunburst into that group, a box drills the treemap down with a breadcrumb to climb back up, and the tree has buttons to open or close one level at a time.











Sheet 05 of 09/3D
The graph and the globe in 3D
In the 3D graph each process is a node colored by its stakeholder group. The edges are the folder tree, plus three kinds you can switch on for wiki links, shared tags and links between stakeholder groups.
The globe has six layouts and animates between them. In Bands each stakeholder group gets its own band of latitude, with its stages spread around it. Layered keeps each group in one patch and sets how deep each point sits by its stage, or by another field picked in the Depth menu.





Sheet 06 of 09/Explore
Finding one process
Clicking a node or a table row opens a detail panel with the process code, contractor, stage, tier and the standards it references.
Picking a stakeholder chip narrows the sidebar as well, so it only lists that group's contractors, stages and sub-stages, and every view redraws with just that group.
The Explorer Lens dims everything except what you hover. It can show one node, its neighbours or its whole branch, with a card for its category, stage and level. The radial tree has a lens of its own that lights one branch and shows its process count.
I also built hand tracking with MediaPipe's hand landmark model, which loaded the first time you turned it on. In orbit mode the center of your open palm turned the camera and a pinch zoomed. In pointer mode your index finger moved a cursor and a pinch clicked. A pinch was the thumb tip and index tip less than 0.06 apart in MediaPipe's image coordinates for three frames in a row. It isn't wired into the last build, but the code is still in the repo.






Sheet 07 of 09/Desktop
A desktop app, then back to the browser
On March 16 I started a desktop version in Tauri, with a Rust backend reading from SQLite. The plan was to stop loading the 25 MB JSON in the browser and ship a Windows installer and a Mac build. On March 30 I took the Tauri backend out again and made it a static web app with a GitHub Pages deploy. On the last day I moved the 3D graph from 3d-force-graph to AntV's G6.
Sheet 08 of 09/Video
Tools for the demo videos
The client sent me some product videos posted on X as examples and wanted clips like them for the app. I planned 33 short clips, 10 to 30 seconds each, recorded in dark mode with music and no voiceover.
First I built a Video Studio inside the app. You describe a demo in a chat, Claude or an OpenAI model turns it into a list of app actions, and the app plays them while it records itself. It's commented out in the last build.
Then I built a separate Video Maker for editing the recordings. It has a clip library, in and out points, a timeline with a caption track, and export to MP4 or WebM through ffmpeg running in the browser. It can send frames from a clip to Claude for a title, tags and captions, or ask it which parts to keep to cut the clip to 10, 20, 30 or 40 seconds. It also flags stretches where the screen stops moving.



Sheet 09 of 09/Issues
Known issues in the last build
Search, Agents, Projects and 7 Layer Analysis in the dashboard still say Coming soon, and the chat box on the home page isn't connected to anything. The sign-in page checks the password in the browser, so it only keeps out casual visitors. The layout also doesn't fit a phone screen.
In the last build the globe comes up empty. The last commit swapped in G6 and stopped loading the OrbitControls script, and the globe only aims its camera at the sphere through those controls. The globe pictures on this page come from the March 30 build, the last one before that change.