Spencer Rose Software Engineer Interactive Systems

Hi πŸ‘‹

Thanks for stopping by! My work speaks for itself, and so do I. Here's a bit about me:

🧍 Name: Spencer Rose

🌎 Location: Toronto / Ontario / Canada

πŸ’ Domain: Full-stack, mostly front-end, and mostly JavaScript.

πŸ§™ Specialties: Low-level frontend JavaScript. Design systems. Creative development. Solution architecture.

Work

  • Cadre

    ✨ Pull requests for physical objects β€” browser-native 3D CAD with live collaboration. ✨

    Project Creator Β· Principal Developer

    Cadre is a browser-based solid modelling tool built for makers who want to go from idea to printable STL fast, and share that process with collaborators β€” without asking anyone to install software.

    The pitch is simple: open a tab, build something, send a link. No account required. Works offline.

    The Collaboration Model

    The most interesting thing about Cadre isn't the geometry β€” it's the collaboration workflow. It's modelled loosely on pull requests:

    1. A host designs a model and shares a live room link
    2. A viewer joins and watches edits in real time, with remote cursors visible in the 3D viewport
    3. The viewer can fork the session into their own local copy, make changes, and submit a suggestion
    4. The host reviews the diff and accepts or discards with one click

    This gives design feedback a structure it usually doesn't have. Instead of sending annotated screenshots back and forth, a collaborator can just show you what they mean.

    Why Rust/WASM

    CSG boolean operations β€” union, subtract, intersect β€” are expensive. Doing them in JavaScript on the main thread would mean jank. Cadre's geometry kernel is written in Rust and compiled to WebAssembly, which means the heavy work runs in compiled code, off the main thread, and the UI stays at 60fps during complex operations.

    The kernel owns all geometry. The React layer never touches raw vertex data β€” it dispatches commands and receives lightweight JSON metadata back. Mesh buffers only cross the WASM boundary twice: once for rendering (interleaved position + normal arrays for Three.js), and once for export.

    The architecture looks like this:

    1React 19 + Three.js β†’ WASM Bridge β†’ Rust Kernel 2 (UI, viewport) (singleton) (geometry, CSG, 3 snap, history) 4

    What the kernel actually does

    • CSG via a BSP-tree implementation (Evan Wallace's approach) β€” builds a binary space partition from a triangle soup, classifies and clips polygons recursively, merges the result into a single indexed mesh
    • Snap engine using a spatial hash to partition scene AABBs into grid cells for O(1) range queries, with per-axis lock hysteresis to prevent jitter during drags
    • Scene graph as a HashMap<u32, SceneNode> for O(1) lookup + an ordered Vec<u32> for insertion order, with each node retaining its original parametric inputs for re-editing
    • Undo/redo via a command pattern storing forward/reverse deltas, bounded at 100 entries
    • Import/export: STL (binary + ASCII auto-detect), OBJ with n-gon triangulation, binary STL output compatible with PrusaSlicer and Cura

    What I found interesting to build

    The WASM integration took the most care. The kernel loads as a lazy singleton β€” the WASM binary is fetched and compiled once, and every store action that needs geometry goes through a single bridge module. Getting that boundary right (what belongs in Rust vs. what belongs in Zustand) shaped the whole codebase.

    The collaboration layer was the other genuinely tricky part. Supabase Realtime handles presence and broadcast, but the fork-and-suggest workflow required designing a mini state machine: viewer mode β†’ fork mode β†’ suggestion submitted β†’ host review β†’ accepted or discarded. When VITE_SUPABASE_URL isn't set, all of that code is tree-shaken and the app behaves as a fully local, offline tool β€” no dead imports, no runtime errors.

    Tech

    Rust Β· WebAssembly Β· React 19 Β· Three.js Β· @react-three/fiber Β· Zustand Β· Supabase Β· Vite Β· TypeScript

  • League

    ✨ Platform engineering for enterprise digital health, serving millions of members. ✨

    Senior Software Engineer II Β· Platform

    What is League?

    League builds a digital health platform that enterprise clients use as the foundation for their member-facing health apps. The platform handles everything from benefits management and care plans to health assessments and activity-based engagement. League sells extensibility: a configurable, white-label system that lets clients deliver their own branded health experience without building from scratch.

    My first few years were centred on Health Journey β€” the engagement layer of the platform, where users complete Activities, earn points, and build health habits. Over time, my scope expanded into the platform layer itself.

    What I own

    Masonry is League's server-driven UI framework. Rather than shipping hard-coded screens, the backend sends a JSON tree of node types, and the web client renders them dynamically. This means content authors and product managers can build and modify experiences without touching frontend code.

    Genesis is League's design system β€” the component library and token system that all of Masonry's renderers and client-facing surfaces are built on top of.

    Owning both means I'm responsible for the layer of infrastructure that most other teams build on top of. Changes I make either accelerate or complicate work for a lot of people, which makes the work interesting.

    Things I've built

    Renderer Style Overrides Before this, client teams who needed to customise the look of a Masonry component had to fork code or work around the system. I designed and shipped an override API β€” css and className props β€” across every Masonry renderer, giving integrators a clean, documented customisation path without touching internals. It's now the standard pattern across the platform.

    A browser-based IDE for tailored for content authoring. A configuration tool that previously required engineers to hand-edit raw JSON got a proper editor: YAML and JSON support, JSON-schema validation, real-time feedback, and full accessibility compliance. I took it from proof-of-concept through to production, including the backend migration and form entity integration.

    Cross-platform migration strategy When the team needed to migrate the Activities platform to Masonry 2.0, I authored the technical strategy across all four platforms β€” Web, iOS, Android, and Backend β€” despite Web being my home platform. Getting alignment on an approach before anyone wrote code was the part that mattered, and scoping it across platforms I don't own daily made it an interesting problem.

    Proxy-based API migration When Genesis moved from an illustrative to a descriptive icon token system, I needed to migrate all consumers without breaking anything. I used a JavaScript Proxy object to intercept calls to the deprecated API and transparently route them to the new one, with deprecation warnings, while both systems coexisted. A migration that should never surprise anyone downstream.

    Claude Code Skills: /write-spec and /write-plan I built a pair of Claude Code skills for the Member Portal team that turn a feature description into a structured spec or implementation plan, validated against the actual codebase. The goal was to replace ad-hoc AI prompting with a repeatable, verifiable workflow β€” something you could commit to rather than just read and discard.

    Support Summarizer As the platform scaled, Slack support threads were getting answered and then lost. I built an automation using Gemini that captures a thread with a Slack shortcut and converts it into a structured Confluence page β€” turning a one-off answer into permanent, searchable documentation.

    On AI and developer tooling

    I've been thinking a lot about how AI changes the way platform teams work β€” not as a productivity trick, but as infrastructure you build into the workflow. The skills, the summarizer, a multi-stack dispatch workflow that fans out a feature implementation across Web, iOS, Android, and backend repos in a single session β€” these are experiments in where the real leverage is.

  • Marjoram

    ✨ A signal-driven widget SDK β€” the middle ground between a framework and raw JS. ✨

    Project Creator Β· Principal Developer

    Marjoram is a tiny, 0-dependency library for building self-contained, stateful UI widgets on the web. It's designed for situations where React (or any other framework) isn't on the table β€” think embeds, third-party widgets, cookie banners, or any context where you need to drop a UI into a page you don't control.

    The core idea: give developers a clean separation between state and view β€” a ViewModel pattern β€” without the bloat of a full framework.

    What makes it interesting?

    The first version of Marjoram used JavaScript Proxy objects to wire state directly to DOM text and attribute nodes. No virtual DOM, no diffing, no reconciler β€” just mutations to the exact nodes that care about a given value. That meant no unnecessary re-renders by design.

    The current version goes further. Marjoram is now built on a fine-grained signal graph β€” the same reactivity primitive that's made SolidJS and Preact Signals popular. Computed properties only re-evaluate when their actual dependencies change, DOM updates are batched through the microtask queue, and html tagged templates parse once and clone on reuse. The result is genuinely fast: ~2,800 property updates per millisecond in benchmarks.

    On top of that, createWidget mounts into a closed Shadow DOM, which means styles are fully isolated from the host page. You can drop a Marjoram widget into any site β€” React, jQuery, plain HTML β€” and it won't bleed.

    Why I built it

    I kept running into situations at work where the solution to a scoped UI problem was "add React" β€” which meant adding a build step, a runtime, and a pile of dependencies to something that really just needed a counter or a status banner. I wanted a library that was genuinely small, genuinely self-contained, and genuinely easy to reason about. Marjoram is my answer to that.