Spencer Rose Software Engineer Interactive Systems
Hi π
Thanks for stopping by! My work speaks for itself. Here's a bit about me anyways:
π§ 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. Product Engineering and the messy intersection of code and experience.
Work
Cadre
β¨ An AI co-reviewer for parametric CAD β catch the manufacturing problems in a part before your printer does. β¨
Founder Β· Cadre3D Inc.
Cadre is an AI co-reviewer for parametric CAD. You model a part in the browser β sketch a profile, extrude it, fillet the edges β then ask AI to review it for manufacturability: thin walls, sharp internal corners, steep overhangs, features too small to print. Each issue comes back as a clickable flag that frames the problem in the viewport, alongside a concrete
old β newparameter change you can accept in one click.No install, no account to try it. It runs in any modern browser and it's free during the alpha.
The idea I'm proudest of
AI suggestions and human suggestions go through the same pipeline. A collaborator can open a share link, fork your model, change something, and submit it β and it lands in your review inbox right next to the AI's flags, as the same kind of typed parameter diff. You accept or discard either one with a click, and every accept lands as a single entry in the feature-tree history. Review is review, whether the reviewer is a person or a model.
Why Rust and WebAssembly
CSG booleans, snapping, and mesh repair are CPU-heavy and run on the main thread. In JavaScript that means jank. Cadre's geometry kernel is written in Rust and compiled to WebAssembly, so the heavy work runs as compiled code and the editor holds 60fps through operations that would stutter in pure JS.
The kernel owns every triangle. The TypeScript layer never builds or mutates a mesh β it dispatches commands and reads back JSON metadata and read-only render buffers. Getting that boundary right β what belongs in Rust, what belongs in the React/Zustand layer β shaped the whole codebase, and it's enforced now by lint rules and architecture tests.
What the kernel does
- Parametric modelling β a 2D sketcher (lines, arcs, circles, profiles on any plane or face), a feature tree of extrude / revolve / fillet operations, named variables and expressions (
width / 2), and re-editable primitives. Change a parameter upstream and the tree recomputes. - CSG via a BSP-tree β union, subtract, intersect β with a post-boolean repair pass.
- Stable topology β vertex / edge / face IDs that survive transforms and booleans, so selections and fillets stay attached to the geometry they were made on.
- Snapping via a spatial hash with per-axis lock hysteresis, 100-deep undo/redo over every mutation, and STL / OBJ import and export.
Making the AI honest
The hard part of an AI reviewer is that it's easy for it to guess. So the kernel measures the things the AI is allowed to talk about β wall thickness by inward ray casting, overhang against the build direction β and the prompt requires every flag to cite the measured value, not infer it from a bounding box. The model runs server-side in an Edge Function, never in the browser, behind server-enforced quotas and cost caps. A small public API returns any review as structured JSON for downstream agents.
Where it's at
Cadre is in public alpha as Cadre3D Inc. β a free tier with an AI quota now, a paid tier at graduation. It's the first thing I've taken end to end as a product rather than a project: the kernel, the app, the pricing, and the unglamorous parts like row-level-security policies and abuse guards. That's been the real education.
Tech
RustΒ·WebAssemblyΒ·React 19Β·Three.jsΒ·@react-three/fiberΒ·ZustandΒ·SupabaseΒ·Anthropic ClaudeΒ·ViteΒ·TypeScript- Parametric modelling β a 2D sketcher (lines, arcs, circles, profiles on any plane or face), a feature tree of extrude / revolve / fillet operations, named variables and expressions (
League
β¨ Platform engineering for enterprise digital health, serving millions of members. β¨
Senior Software Engineer II Β· Platform
What is League?
League is a digital health platform that enterprise clients build their member-facing health apps on top of β benefits management, care plans, health assessments, activity-based engagement. The product is extensibility: a configurable, white-label system that lets clients ship their own branded health experience without building from scratch.
My first few years centred on Health Journey β the engagement layer, where members complete Activities, earn points, and build health habits. Over time my scope expanded into the platform itself.
What I owned
Masonry is League's server-driven UI framework. Instead of shipping hard-coded screens, the backend sends a JSON tree of node types and the web client renders it dynamically β so content authors and product managers can build and change experiences without touching frontend code.
Genesis is League's design system β the components and tokens every Masonry renderer and client surface is built on.
Owning both meant I was responsible for the layer most other teams built on top of. What I shipped either accelerated or complicated a lot of people's work β which is what made it interesting.
Things I built
Renderer style overrides. Customising a Masonry component used to mean forking code or working around the system. I designed and shipped an override API β
cssandclassNameprops across every renderer β giving integrators a clean, documented path without touching internals. It became the standard pattern across the platform.A browser-based authoring IDE. A configuration tool that once 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. For the Activities move 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 before anyone wrote code was the part that mattered, and scoping it across platforms I didn'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 migrated every consumer without breaking anything: a JavaScript
Proxyintercepted calls to the deprecated API and routed them to the new one β with deprecation warnings β while both systems coexisted. A migration nobody downstream had to notice.Claude Code skills:
/write-specand/write-plan. A pair of skills for the Member Portal team that turn a feature description into a structured spec or implementation plan, validated against the actual codebase β replacing ad-hoc AI prompting with a workflow you could commit to rather than 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 from a Slack shortcut and turns it into a structured Confluence page β a one-off answer becomes permanent, searchable documentation.
On AI and developer tooling
I think 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 a single feature out across Web, iOS, Android, and backend repos in one 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, zero-dependency library (~7KB gzipped) for building self-contained, stateful UI widgets β for the situations where React, or any framework, isn't on the table. Embeds, third-party widgets, cookie banners, feedback forms: anywhere you need to drop UI into a page you don't control.
The core idea is a clean split between state and view β a ViewModel pattern β without the weight of a framework.
What makes it interesting
The first version wired state straight to the DOM with JavaScript
Proxyobjects: mutations went to the exact text and attribute nodes that cared about a value. No virtual DOM, no diffing, no reconciler β no wasted re-renders by design.The current version (v1.2) runs on a fine-grained signal graph β the reactivity primitive behind SolidJS and Preact Signals. Computed values recompute only when a real dependency changes, DOM writes batch through the microtask queue, and
htmltagged templates parse once and clone on reuse. It's quick: ~2,800 property updates per millisecond in the benchmark suite.The part I find most satisfying is what came next. The reactivity layer is now shaped to the TC39 Signals proposal β
SignalOptions, lifecycle hooks, aWatcher-style primitive, an introspection namespace β andstore(), the deep-reactive state container, is rebuilt entirely on those public primitives, with no private escape hatches into the engine. That was the real test: if a genuine deep-reactivity feature can be built on nothing but the spec surface, the spec surface is sufficient. (I keep the framing honest, too β it's spec-shaped and push-based, not a glitch-free pull graph like Reactively.)createWidgetmounts into a closed Shadow DOM, so styles are fully isolated β drop a Marjoram widget into React, jQuery, or plain HTML and nothing bleeds in either direction.Why I built it
I kept hitting problems at work where the answer to a scoped UI need was "add React" β a build step, a runtime, and a pile of dependencies for something that just needed a counter or a status banner. I wanted something genuinely small, genuinely self-contained, and genuinely easy to reason about. Marjoram is my answer, and it's on npm now.