{
  "$schema": "https://jsonresume.org/schema/1.0.0/resume.json",
  "basics": {
    "name": "James M",
    "label": "Software Engineer",
    "summary": "Portfolio of 19 software projects spanning C++, Python, TypeScript, Go, JavaScript, HCL, PowerShell.",
    "url": "https://jm-portfolio-5afqr6ijoq-uc.a.run.app/",
    "profiles": [
      {
        "network": "GitHub",
        "username": "virtualhealthcitizen",
        "url": "https://github.com/virtualhealthcitizen"
      }
    ]
  },
  "skills": [
    {
      "name": "C++",
      "keywords": [
        "LRGQ",
        "Ashenreach",
        "ue5-experiments"
      ]
    },
    {
      "name": "Python",
      "keywords": [
        "ffmpeg-util",
        "adk-sandbox",
        "Token Validator"
      ]
    },
    {
      "name": "TypeScript",
      "keywords": [
        "Forge Engine",
        "cloud-portfolio",
        "Workflow Dispatcher",
        "PH1",
        "Pipeworks",
        "Orrery"
      ]
    },
    {
      "name": "Go",
      "keywords": [
        "go-labs"
      ]
    },
    {
      "name": "JavaScript",
      "keywords": [
        "Recall",
        "Spinnaker Sandbox",
        "sketchbook"
      ]
    },
    {
      "name": "HCL",
      "keywords": [
        "GCP Terraform Labs",
        "AWS Terraform Infra"
      ]
    },
    {
      "name": "PowerShell",
      "keywords": [
        "NetSentry"
      ]
    }
  ],
  "projects": [
    {
      "name": "LRGQ",
      "description": "2D game engine in C++ with a built-in editor, on SFML or raylib",
      "highlights": [
        "Fixed-timestep engine loop with scene transitions",
        "Two seams, not one — a draw facade (gfx::IRenderer) and a window/event/input/ImGui boundary, each with an SFML 3 and a raylib implementation, selected together by one LRGE_BACKEND build option",
        "A raylib-only probe target compiles the facade with SFML nowhere in scope, so the seam can't quietly rot — and it doubles as the gate that checks the key mapping is total and injective",
        "Tile-map editor: pan, zoom, content browser, Pawn blueprints with an Event Graph",
        "Synthesized audio + procedurally generated sprites (no asset files)",
        "Multi-session autonomous burndown with a 1-in-3 bug-hunt cadence, gated by 217 headless test cases then a human editor pass — 31 features validated hands-on, 1 pending"
      ],
      "keywords": [
        "game-engine",
        "c++17",
        "sfml",
        "raylib",
        "editor",
        "cmake"
      ],
      "url": "https://jm-portfolio-5afqr6ijoq-uc.a.run.app/#/project/lrge"
    },
    {
      "name": "ffmpeg-util",
      "description": "A media toolkit whose dependency-free core builds the exact ffmpeg command — library, CLI & desktop app",
      "highlights": [
        "The command is the artifact — a dependency-free stdlib core of ~98 argv builders assembles the exact ffmpeg call, so it's testable without ffmpeg installed and --dry-run just prints it",
        "One core, three surfaces — a library, a CLI (with a config file), and an Electron desktop app whose renderer drives a Python FastAPI sidecar (~60 endpoints) re-exposing the same library",
        "~50 operations — convert/trim/concat/thumbnail/probe, CRF/target-size/hardware compression, video FX, colour, audio, speed & GIF",
        "Desktop app: drag-and-drop, source preview, batch mode, cancel, presets/profiles, light/dark, shortcuts, and a live progress bar + ETA from ffmpeg's -progress over SSE",
        "PyInstaller-frozen sidecar (zero Python at runtime), gated by 3 test layers (root pytest + sidecar pytest vs real ffmpeg + node:test + a headless Electron E2E)",
        "Shipped continuously by an autonomous burn loop with a 1-in-3 bug-hunt cadence"
      ],
      "keywords": [
        "ffmpeg",
        "python",
        "cli",
        "electron",
        "fastapi",
        "media"
      ],
      "url": "https://jm-portfolio-5afqr6ijoq-uc.a.run.app/#/project/ffmpeg-util"
    },
    {
      "name": "Forge Engine",
      "description": "A UE5-like game engine built entirely on HTML5",
      "highlights": [
        "WebGPU forward renderer with tiled light binning",
        "Blueprints: data-graph → JS expression codegen",
        "Material graph, physics narrowphase, animation root motion",
        "UE5-style dockable editor panels and play-mode toolbar",
        "Autonomous burn fleet with a 1-in-3 bug-hunt cadence"
      ],
      "keywords": [
        "webgpu",
        "typescript",
        "electron",
        "game-engine",
        "vite"
      ],
      "url": "https://jm-portfolio-5afqr6ijoq-uc.a.run.app/#/project/smol"
    },
    {
      "name": "adk-sandbox",
      "description": "A sandbox of runnable Google ADK agents that pick a tool and answer from the result",
      "highlights": [
        "Four runnable ADK agents, each a directory the runtime discovers by its module-level root_agent",
        "The tool-call loop up front — gemini-2.5-flash reads a function's signature, picks it, calls it, answers from the result",
        "A mock-tool agent (jm_test) runs the identical loop offline so the smoke suite needs no live key",
        "Docs generated from the AST — a Sphinx directive renders each agent's tools from source, so they can't drift",
        "Sphinx site auto-deployed to GCS on every merge, gated behind the pytest suite",
        "Kept green by an autonomous burn loop — one validated item per run, 1-in-3 bug-hunt cadence"
      ],
      "keywords": [
        "google-adk",
        "python",
        "agents",
        "tool-calling",
        "gemini",
        "gcs",
        "sphinx"
      ],
      "url": "https://jm-portfolio-5afqr6ijoq-uc.a.run.app/#/project/adk-sandbox"
    },
    {
      "name": "go-labs",
      "description": "A hands-on Go playground you learn by running — one module, a live browser sandbox",
      "highlights": [
        "Learn by running — one `package main` per directory keeps `go build ./...` green no matter how many examples land",
        "A dependency-free `go:embed` web sandbox that compiles & runs any example (or scratch code) live in the browser",
        "Runs are sandboxed child processes with a hard timeout that kills the whole process tree — a runaway loop can't hang the server",
        "Topics 01–13 + stdlib + testing: basics, functions, structs, maps, pointers, concurrency, error handling — each a runnable note",
        "Importable, tested util package; whole module stays gofmt/vet/build/test green via `make check` + CI",
        "A two-track roadmap: round out the language, then isolated ecosystem tours (net/http, chi/Gin/Echo, cobra, slog, database/sql)"
      ],
      "keywords": [
        "go",
        "learning",
        "playground",
        "concurrency",
        "go-embed",
        "stdlib"
      ],
      "url": "https://jm-portfolio-5afqr6ijoq-uc.a.run.app/#/project/go-labs"
    },
    {
      "name": "Token Validator",
      "description": "A stateless Flask token-validation service and the Electron desktop app that fronts it",
      "highlights": [
        "Delegated trust — POST /api/validate-token proxies Google's tokeninfo; the service stays stateless, database-free and holds no secret of its own",
        "A companion Electron + React + TS desktop app: paste a token, validate, and read the decoded claims — no curl, no Postman",
        "Two validation modes — Direct (client → Google) or Remote (client → the Flask service → Google)",
        "The token is never stored or logged — in-memory only, scrubbed on clear; only UI preferences persist",
        "Readable claims: scope chips, humanized expiry (absolute + 'expires in …'), an ordered table, copy-as-JSON, light/dark theme",
        "Containerized for Cloud Run with a Postman/Newman integration suite; the desktop's pure helpers are vitest-covered"
      ],
      "keywords": [
        "python",
        "flask",
        "oauth2",
        "electron",
        "react",
        "cloud-run"
      ],
      "url": "https://jm-portfolio-5afqr6ijoq-uc.a.run.app/#/project/token-validator-service"
    },
    {
      "name": "cloud-portfolio",
      "description": "A React/TypeScript personal portfolio that ships itself to Cloud Run on every pull request",
      "highlights": [
        "Open a pull request → it's live: cicd.yml deploys the build to Cloud Run on pull_request (not merge), so a change is reviewable at a real URL",
        "Multi-stage Docker build — a node:20 stage builds the bundle, an nginx:stable-alpine stage serves just the static build/ (the toolchain never ships)",
        "React 19 + Vite 6 + TypeScript, MUI 7 on a design-token theme — teal→sky accent gradient, glass surfaces, light & dark modes",
        "Home (react-spring hero + skills + certifications), About, and a Projects page (personal cards + enterprise timeline + GitHub stats)",
        "Migrated off Create React App to Vite 6 + Vitest 4 — dropped a defunct polyfill.io script, pruned deps ~1,500 → 466, zero audit vulns"
      ],
      "keywords": [
        "react",
        "typescript",
        "vite",
        "mui",
        "cloud-run",
        "docker"
      ],
      "url": "https://jm-portfolio-5afqr6ijoq-uc.a.run.app/#/project/cloud-portfolio"
    },
    {
      "name": "Workflow Dispatcher",
      "description": "A client-side React panel that fans GitHub Actions runs out across many repos",
      "highlights": [
        "Fan workflow_dispatch runs out across many repos in one action — sequentially (for…await) or in parallel (Promise.all)",
        "Multi-repo connect with live GitHub-API validation; browse & select workflows across all connected repos",
        "Flexible ref targeting (branch / tag / exact SHA) + arbitrary key/value inputs passed straight into the dispatch payload",
        "A run-history panel — status, conclusion, actor & a link back to GitHub — without leaving the app or pushing a commit",
        "No backend of its own: browser → api.github.com with a Bearer PAT held in memory only, never persisted or logged",
        "Typed Vite + React + Zustand (two small stores), ported from a plain HTML/CSS/JS prototype, with ESLint + CI"
      ],
      "keywords": [
        "react",
        "typescript",
        "vite",
        "zustand",
        "github-actions",
        "cicd"
      ],
      "url": "https://jm-portfolio-5afqr6ijoq-uc.a.run.app/#/project/cicd-frontend-react-ts"
    },
    {
      "name": "Recall",
      "description": "A zero-dependency flashcards app that reviews each card right before you forget it",
      "highlights": [
        "The entire app is one self-contained index.html — no build step, no framework, nothing to install",
        "SM-2-style spaced repetition — each card's interval stretches with its ease as the memory sticks; a 'Study due' queue surfaces only what's due",
        "Basic and fill-in-the-blank cards (with answer alternates) in decks grouped by colour-coded subject; rich sanitised HTML + inline images",
        "Browser-native persistence: IndexedDB primary + a synchronous localStorage cache for instant restore, reconciled by freshest snapshot",
        "Your data stays yours — no account, no server, no network call; JSON export/import for backups and moving decks between devices",
        "A ~90-line zero-dependency Node-stdlib static server + a CI smoke test; dark-default with light & compact density modes"
      ],
      "keywords": [
        "flashcards",
        "spaced-repetition",
        "sm-2",
        "vanilla-js",
        "indexeddb",
        "offline-first"
      ],
      "url": "https://jm-portfolio-5afqr6ijoq-uc.a.run.app/#/project/recall"
    },
    {
      "name": "GCP Terraform Labs",
      "description": "jm's Google Cloud footprint as Terraform — the live portfolio infra, plus a library of self-destroying API experiments",
      "highlights": [
        "Two halves under one repo + GCS state backend: the LIVE portfolio infra (gcp/dev) and a library of ephemeral, self-destroying API experiments (gcp/<name>-demo)",
        "gcp/dev provisions the real infrastructure — SAs + Workload-Identity/IAM for GitHub-Actions Cloud Run deploys, KMS/CMEK + public buckets, Secret Manager, Pub/Sub, Cloud SQL — and the live app backends (jm-likes ♥ + murmur-chat) + the desktop auto-update proxy",
        "murmur-chat — a full moderated chat API on Cloud Run (9 endpoints, ~560 LOC): post/edit/soft-delete, transactional reaction toggles, pins, and a reports→moderation-queue path where enough DISTINCT reporters escalates to a shadow-ban the response never reveals",
        "Presence as its own write: online/away status the client's own tab visibility sets, a truncated typing preview, and a readAt high-water mark for \"seen\" receipts — all rate-limited, because unbounded presence POSTs were a free-tier cost DoS",
        "The ephemeral pattern: each demo spins up a throwaway NO-BILLING GCP project, proves one API, captures what the showcase needs, then destroys itself — zero cost, nothing left behind",
        "A dozen self-destroying experiments shipped: gemini, translate, pub/sub, firestore, vision, bigquery, cloud-scheduler, artifact-registry, cloud-functions, cloud-run, secret-manager & an enrichment-pipeline",
        "All in Terraform on google/google-beta ~>6.0 with a GCS remote state backend (lofty-root-tf-state) + a Terraform CI workflow + Sphinx docs"
      ],
      "keywords": [
        "terraform",
        "gcp",
        "infrastructure-as-code",
        "iam",
        "cloud-run"
      ],
      "url": "https://jm-portfolio-5afqr6ijoq-uc.a.run.app/#/project/gcp-terraform-labs"
    },
    {
      "name": "AWS Terraform Infra",
      "description": "Reusable AWS Terraform modules & examples — provisioning cloud architectures, validated without credentials",
      "highlights": [
        "Reusable, independently-exampled modules — network, messaging, compute, iam, monitoring — each with its own runnable examples/ root you can lift into any project",
        "Validated with NO AWS credentials — terraform fmt + per-root validate + tflint, gated in CI and pre-commit (plan/apply deferred until creds exist)",
        "Composes into thin dev / staging / prod roots with isolated S3 state — the flagship worked example: SentryStream, a telemetry-ingest platform wired end to end",
        "The building blocks: a two-AZ VPC (NAT, internal NLB, flow logs, VPC endpoints), SNS → SQS fan-out with per-consumer DLQs, ECS Fargate autoscaling, least-privilege IAM, a CloudWatch dashboard",
        "global/bootstrap foundation (encrypted/versioned S3 state, KMS, multi-region CloudTrail, DynamoDB lock, TerraformDeploy IAM) + IAM Identity Center SSO / OIDC on hashicorp/aws ~>6.0"
      ],
      "keywords": [
        "terraform",
        "aws",
        "infrastructure-as-code",
        "modules",
        "ecs",
        "vpc"
      ],
      "url": "https://jm-portfolio-5afqr6ijoq-uc.a.run.app/#/project/terraform-aws"
    },
    {
      "name": "Ashenreach",
      "description": "A first-person RPG built entirely in C++ on UE 5.3 — the Field Guide's reference project",
      "highlights": [
        "Every system in plain C++ (module Ashenreach, AAsh…/UAsh…/FAsh…/EAsh… naming) — no Blueprint gameplay, no GAS, so a reader can follow the whole call path",
        "A from-scratch animation stack: directional strafe blend space, gaits, rotation modes, per-armament linked anim layers, crouch, airborne states, and a spine split that layers upper-body montages over a live stride",
        "Combat feel as engineering: a phase-driven montage time warp that makes a controlled mocap swing commit, and a held shield guard whose raise→loop seam is crossfaded guard-to-guard so no frame of locomotion flashes through",
        "Live pose-trim knobs — per-stance rotator pairs composed in C++ and applied by component-space Transform-Modify-Bone nodes, tunable in the editor with no recompile and zero-default no-op",
        "AshAnimPolish: a UE 5.3 editor-Python toolkit that bakes per-phase time warps, contact holds and spring follow-through into duplicated AnimSequences, gated by a headless commandlet test",
        "A seeded procedural dungeon generator (rooms · caves · mazes) extruded into walkable UProceduralMeshComponent geometry, with locks, keys and solvable population",
        "Every chapter is compile-verified headlessly (UBT exit 0) and PIE-validated before it ships — the book never documents an unbuilt system"
      ],
      "keywords": [
        "unreal-engine",
        "ue5",
        "c++",
        "rpg",
        "animation",
        "procedural-generation"
      ],
      "url": "https://jm-portfolio-5afqr6ijoq-uc.a.run.app/#/project/ashenreach"
    },
    {
      "name": "ue5-experiments",
      "description": "Unreal Engine 5 C++ gameplay experiments for a 2D side-scroller",
      "highlights": [
        "Procedural-animation scene components from engine primitives: boids swarm, interfering wave field, golden-angle phyllotaxis bloom — code-driven, no animation assets, editor-overridable mesh",
        "DirectionalMovementComponent: sinusoidal-oscillate and open/close-toggle movers (with phase offset + Reset) for platforms, doors, and lifts",
        "Variable-height platformer jump as a Blueprint function library — physics only, animation left to the caller",
        "Niagara debuff/buff particle library that attaches effects to a character and follows them",
        "In-world retro terminal + cartridge system: keystroke capture, scrollback, cursor editing, wrapping, rendered via a UMG delegate",
        "Self-contained 3D analog clock built from engine primitive meshes, hands tracking real machine time"
      ],
      "keywords": [
        "unreal-engine",
        "ue5",
        "c++",
        "procedural-animation",
        "paperzd"
      ],
      "url": "https://jm-portfolio-5afqr6ijoq-uc.a.run.app/#/project/ue5-experiments"
    },
    {
      "name": "NetSentry",
      "description": "A defensive-security sentry for one household's LAN, PC, and Cloud Run apps",
      "highlights": [
        "Home-LAN discovery + service scan diffed against a known-good baseline → toast on any new device or open port (no nmap), plus a fast between-sweeps ARP watch",
        "Windows hardening audit scored against a baseline: SMB/LLMNR/print-spooler surface, Defender/AV state, SMBv1, BitLocker",
        "Cloud Run defense: request logs → visitor classes + deduced intent + scanner detection, and an IAM audit flagging any PUBLIC (allUsers) invoke for review",
        "Secrets hygiene: a gitleaks-style sweep of the operator's OWN repos → a redacted findings report; an orchestrator + WPF dashboard + toast + a daily scheduled sweep",
        "Authorized own-assets only — secrets, device MACs, and raw logs gitignored, with redacted examples committed"
      ],
      "keywords": [
        "security",
        "powershell",
        "network-scanning",
        "cloud-run",
        "windows"
      ],
      "url": "https://jm-portfolio-5afqr6ijoq-uc.a.run.app/#/project/netsentry"
    },
    {
      "name": "Spinnaker Sandbox",
      "description": "Master Spinnaker through small runnable labs — pipelines-as-code with a local Lab Console",
      "highlights": [
        "30+ self-contained labs: a Spinnaker curriculum from linear deploy → strategies → triggers/artifacts → SpEL → Kayenta canary, each a real pipeline.json + README",
        "Dependency-free structural gate: an authoritative PowerShell validator (unique refIds, acyclic DAG, no dangling edges, required fields) with a parity Bash/jq port",
        "Local Lab Console (static ui/) renders each pipeline's stage DAG and streams simulated per-stage console output — no live cluster required",
        "Self-test catches every failure mode (cycle, dangling edge, duplicate refId, missing field) so the gate can't silently become a no-op",
        "Everything validates locally with no live Spinnaker; a later adapter swaps the simulator for a real Gate/Orca to tail live runs"
      ],
      "keywords": [
        "spinnaker",
        "continuous-delivery",
        "pipelines-as-code",
        "kubernetes",
        "devops"
      ],
      "url": "https://jm-portfolio-5afqr6ijoq-uc.a.run.app/#/project/spinnaker-sandbox"
    },
    {
      "name": "PH1",
      "description": "A procedural space sandbox, built in Phaser 3",
      "highlights": [
        "A seeded universe — sectors, planets and asteroid fields generated from one per-account seed",
        "An economy you work — mine, refine, manufacture, market and fit, each a pure tested system",
        "Ship combat flown in its own scene, over a layered tank",
        "Planetary surfaces you land on and never leave — walk them, dig them, build on them",
        "A discipline and job career you level by doing",
        "Generated, not drawn — the art is made in code",
        "Pure model first, scene glue after — the rules run headlessly, under test"
      ],
      "keywords": [
        "phaser",
        "typescript",
        "vite",
        "procedural-generation",
        "webgl"
      ],
      "url": "https://jm-portfolio-5afqr6ijoq-uc.a.run.app/#/project/nebula-drift"
    },
    {
      "name": "Pipeworks",
      "description": "A Factorio-inspired management sim for Spinnaker CI/CD pipelines — build the delivery factory",
      "highlights": [
        "A CI/CD org modelled as a Factorio factory — commits arrive like ore, flow bake → test → deploy down a DAG; DORA (deploy frequency, lead time, change-failure) is the score, with a per-key breakdown",
        "A drag-to-build pipeline editor + a growing stage catalog — Manual Judgment, Check Preconditions, Run Job, recurring deploy-freeze windows; cycles are illegal moves that gate execution",
        "Multi-environment promotion — proven artifacts promote dev → staging → prod as linked pipelines (bake once, deploy many), each pre-prod stage a regression gate, rendered as contiguous board zones",
        "Cross-service dependencies — a service can wait on another; while the dependency is unhealthy the dependent's runs hold as visible backpressure, and a cycle guard rejects a dependency loop that would deadlock the chain",
        "A ship-to-unlock technology tree — the advanced catalog (stage types, canary, ops modules) gates behind engineering capability earned by deploying; progress and production are the same act",
        "Deployment strategy as a risk/cost/speed dial (Highlander / Red-Black / Rolling / Canary + opt-in Kayenta canary scoring) → versioned server groups with rollback to a standby",
        "Layered pressure — capacity brownout, finite bake/deploy resource pools, perishable artifacts (TTL), budget-draining incidents, an evolution-factor fragility ratchet, and a mounting demand-pressure antagonist so standing still loses",
        "Finite regional compute that depletes and forces expansion — per-region fuel, per-region agent pools you must staff, and a relocate-service lever — plus a slot-budgeted operator capability loadout and fog-of-war observability (the equipment grid without the avatar)",
        "An optimization layer — modules/beacons-style speed upgrades, a compute-specialised agent class, and Factorio-quality reliability tiers — each a non-dominant tradeoff locked by a headless balance sweep",
        "Playable from the first minute — first-run onboarding, an in-game Player's Manual, a directives milestone ladder, a 'one thing to fix now' alert strip, juiced audio/visual feedback, and a diagnosis layer (bottleneck highlight, throughput sparklines, agent-utilisation) + 1×/2×/4× speed control",
        "It teaches itself — an inverted opening (hand-deploy until demand out-runs you, then you're handed the machine), a self-ticking Runbooks menu of 9 CI/CD lessons, a just-in-time coach, progressive HUD disclosure, and a self-play attract demo you can take over mid-run",
        "A mastery ceiling you can see — a three-axis scorecard (throughput vs stability vs efficiency) on structurally-opposed axes the balance sweep proves non-dominated, plus Steady / Calm / Chaos difficulty storytellers. A personal best has to be earned (a run must be two minutes in and ten deploys deep before it banks one — two axes used to hand out a perfect 100 in the opening seconds, when nothing shipped means nothing failed), and each axis reports where the run sits as a percentile against a distribution swept from the simulation itself",
        "A AAA presentation layer over the sim — design tokens and a named type scale, a density setting, glass surfaces over the live board, a selective glow/bloom layer, a homegrown tweener driving success pops, failure impacts and event-driven screen shake, MSDF board labels crisp under zoom, and sound cues for both the world and your own clicks",
        "Two of the polish items were really reachability — a pan/zoom camera, because past roughly nine services the board grew taller than the canvas and those lanes were gone rather than merely off-screen (still running, still consuming capacity, with no way to look at them), and per-lane dirty-tracking, because redrawing every lane every frame was the frame budget at scale",
        "Nine releases shipped (v0.1.0 Groundwork → v0.9.0 Onboarding & Teach) with v0.10.0 AAA UI & Juice in flight — a pure, deterministic sim core: the spinnaker-sandbox rules kernel, 438 node:test cases + a headless 240s smoke sim"
      ],
      "keywords": [
        "pixijs",
        "react",
        "typescript",
        "vite",
        "spinnaker",
        "ci-cd",
        "simulation",
        "webgl"
      ],
      "url": "https://jm-portfolio-5afqr6ijoq-uc.a.run.app/#/project/pipeworks"
    },
    {
      "name": "sketchbook",
      "description": "A p5.js sketchbook where algorithms render as live generative art",
      "highlights": [
        "Research-backed graphics & animation quality roadmap — 58 items across 7 phases (ROADMAP.md), one minor release per phase",
        "The p5 upgrade already paid off — v0.3.0 moved the collection 1.6.0 -> 1.11.13 behind a smoke harness, unlocking framebuffers, image-based lighting & WebGL2 on the 1.x line; only shader hooks & instancing still need a 2.0 jump",
        "111 standalone p5.js sketches across 22 topics — algorithm visualizers + generative shaders, 105 of them in WebGL",
        "Preview-gated playable reel of the real sketches on vendored p5 1.11.13, alongside the original hand-listed launcher",
        "'The Bench' — an opt-in shared runtime under a zero-side-effect contract: 8 modules (AA/DPR canvas, pausable clock, springs & easing, transport bar, touch-capable orbit camera, auto-hide chrome, fullscreen, seed<->URL), 80 Node unit tests + an 11/11 real-p5 browser harness, 15 sketches adopted",
        "A generated, manifest-driven gallery — topic chips, text search, shareable deep-link routes, per-card copy-embed, and live thumbnails capped at ten so 105 WebGL contexts never spin up at once",
        "Grounded in a measured audit + verified deep research: the antialiasing sweep is complete (all 105 WebGL sketches antialiased, up from 6 after the first G1 pass), so the remaining headroom is colour management, the p5 2.0 jump & Bench adoption"
      ],
      "keywords": [
        "p5js",
        "creative-coding",
        "webgl",
        "algorithms",
        "generative-art"
      ],
      "url": "https://jm-portfolio-5afqr6ijoq-uc.a.run.app/#/project/processing-sandbox"
    },
    {
      "name": "Orrery",
      "description": "A native control panel for the whole portfolio — it runs the commands itself, with no agent in the loop",
      "highlights": [
        "Runs the real commands — git, gh, npm, gcloud, terraform, PowerShell — spawned directly and streamed live; no agent in the loop at runtime and no service in the middle",
        "59 operations as DATA, not code paths — the renderer asks by operation id and cannot ask for a command, so a parameter is always an argv element (a branch named `a&whoami` is a name, not an injection)",
        "Dry run before anything spawns — the fully-resolved argv, the working directory, and whether it goes direct or via cmd.exe; terraform-plan discipline applied to shell commands",
        "Friction scales with blast radius — read/local run straight through, remote takes a confirmation, destructive makes you type the target's name; Safe Mode un-registers dangerous operations rather than blocking them, so there is nothing to mis-click",
        "The Windows process layer is the hard part — own PATH+PATHEXT walk (Node ignores PATHEXT), ArgvQuote-quoted cmd.exe routing for .cmd shims (Node won't spawn them since CVE-2024-27980), taskkill /T /F so orphans can't hold locks, and UTF-8 forced into every child",
        "Jobs live in the main process with a concurrency queue, sticky terminal states, and a ring buffer that reports what it evicted — log deltas batched at 32ms because one IPC message per line costs more than a second of IPC per second of output",
        "An auto-updater rebuilt from a four-cause post-mortem — progress synthesised from the feed's file size (survives a missing Content-Length), differential ranges off (a single-range server doubles every download), a strict-newer guard at both events, and eight distinguishable error classes instead of one",
        "The fleet dial is the name made literal — burn loops fire on a delay-compensated grid, and drawn as concentric rings with the fire minutes marked, that schedule is an orrery"
      ],
      "keywords": [
        "electron",
        "typescript",
        "react",
        "vite",
        "devtools",
        "automation",
        "gcp",
        "control-panel"
      ],
      "url": "https://jm-portfolio-5afqr6ijoq-uc.a.run.app/#/project/orrery"
    }
  ],
  "meta": {
    "canonical": "https://jm-portfolio-5afqr6ijoq-uc.a.run.app/resume.json",
    "version": "v1.0.0"
  }
}
