Skip to content

Selected Work · 制作

Work

Things I’ve designed and shipped. The flagship builds are full case studies — scroll through each — with the rest of the catalogue in brief below.

03 case studies · 03 more · scroll to begin

Selected case studies

HX-001 · B2B AI SaaS Platform

Halix Solutions

LiveCo-Founder · Technical2025 — Present0 → 1 · FULL UI/UX

Halix Solutions — view 1 of 7
Halix Solutions — view 2 of 7
Halix Solutions — view 3 of 7
Halix Solutions — view 4 of 7
Halix Solutions — view 5 of 7
Halix Solutions — view 6 of 7
Halix Solutions — view 7 of 7

Halix Solutions is an AI-powered B2B SaaS for digital marketing agencies. As technical co-founder, I took it from zero to a live, paying product — and I was the sole technical owner, with no separate engineering team behind me. I owned the full UI/UX across two surfaces: the public marketing site and the authenticated, multi-tenant in-app workspace. Behind the interface sit a multi-stage LLM research pipeline, Stripe billing, and security hardening. The stakes were plain: ship something agencies would actually pay for, then keep it running in production.

Sole technical owner, directing the agents that wrote the code

I built the entire codebase without a separate engineering team. The model: I directed AI coding agents (Claude Code) and owned the parts that don't delegate — architecture, code review, and every technical decision. The agents typed; I decided what got typed and what got rejected. That meant reading every diff, drawing the system boundaries, and choosing the stack. Next.js (App Router), React, TypeScript, Tailwind, and shadcn/ui on the front; Supabase for Postgres, Auth, and Row-Level Security behind it. It's a different way to ship software, and it scales one person across a full product without lowering the bar on what actually merges.

  • Architecture, code review, and technical calls stayed with me
  • Frontend: Next.js, React, TypeScript, Tailwind, shadcn/ui
  • Data layer: Supabase — Postgres, Auth, Row-Level Security

Two surfaces, one design system

The product lives in two places: a public marketing site that has to sell, and an authenticated, multi-tenant workspace that has to work. I owned the UI/UX for both — user flows, wireframes, the visual system, and a reusable component library shared across them. One token set, one component vocabulary, so a button on the landing page and a button inside the app read as the same product. Multi-tenant meant designing for accounts, not just users: clean separation of who sees what, with Row-Level Security enforcing that boundary underneath the interface rather than trusting the UI to hide it.

  • Flows and wireframes through to the visual system
  • One reusable component library across both surfaces
  • Multi-tenant separation backed by RLS, not just UI state

A research pipeline with no research team behind it

The core feature is automated market research: competitor intent-gap analysis and trend reports, built for agencies who'd otherwise do this work by hand. Under the hood it's a multi-stage LLM pipeline — background jobs orchestrated with Inngest so long-running analysis doesn't block a request, writing results into Supabase. I designed the prompts and the end-to-end analysis flow: how raw signals move through each stage and come out as a client-ready report. The hard part was never calling a model once. It was staging the work so it stays reliable when a single job runs long.

  • Inngest orchestrates multi-stage background jobs
  • Owned prompt design and the full LLM analysis flow
  • Outputs: competitor intent-gap analysis and automated trend reports

Billing and security weren't an afterthought

Money and safety are easy to skip in a 0-to-1 and expensive to retrofit, so I wired both in early. Billing runs on Stripe — subscription tiers plus usage-based token-pack pricing, kept in sync through webhooks. Security got real attention: OWASP-style audits, rate limiting, Row-Level Security policies, and secure-by-default function permissions, so the database refuses bad access instead of trusting the app to ask politely. It all ships through Vercel with CI/CD that runs automated test and security gates and applies database migrations before anything reaches production.

  • Stripe: subscription tiers + usage-based token packs via webhooks
  • RLS, rate limiting, OWASP-style audits, locked-down function perms
  • Vercel CI/CD: test + security gates and migrations on every deploy

Shaping the story, not just the software

A technical co-founder who only writes code leaves the product half-sold. I also shaped brand and go-to-market — the landing narrative, the positioning, and the marketing assets that carry them. That work fed straight back into the design: the same read on who the agency buyer is drove both the pitch on the marketing site and the flows inside the app. It's the throughline of the whole project — one person holding the product, the engineering direction, and the story it tells, together, and carrying it from zero to a live, paying SaaS.

Credits
Sole technical owner — no separate engineering team
AI
Directed Claude Code across the entire codebase while owning the architecture, reviewing every diff, and making each technical decision myself.
TypeScriptNext.jsReactSupabaseStripeTailwind CSSVisit

PF-003 · Portfolio Site

This Portfolio

LiveDesign + Build2026DESIGN · BUILD

This Portfolio — view 1 of 3
This Portfolio — view 2 of 3
This Portfolio — view 3 of 3

This is the site you're reading. A motion-led portfolio I designed and built from scratch, with one job: prove the craft it claims instead of describing it. If I say I have a UI/UX eye and can choreograph front-end motion, the site itself has to be the evidence. So every page is its own themed world — sakura day and night, work, contact, craft — sharing one token set, with interactive 3D heroes and scroll-driven motion. Being my own client meant no brief to hide behind, and no one else to blame for a lazy decision.

A portfolio has to pass its own audition

A portfolio claiming UI/UX sensibility and front-end motion can't just list those skills — the page has to be the demo. That set the bar: the build is the argument. I was also my own client, which cut both ways. Total freedom, and nobody else's brief to blame when a decision came out lazy. Every spacing choice, every transition, every theme was a judgment call I had to defend to myself. It sharpened my taste and forced one question onto each interaction — does this earn its place, or is it motion for its own sake? Cuts came easy once that was the test.

One token set drives five themed worlds

Each page is its own world — sakura day and night, work, contact, craft — but they aren't five separate builds. They share a single token set defined CSS-first in Tailwind v4, so a theme is a swap of variables, not a fork of the styling. That keeps the system honest: colour, type, and spacing stay consistent while the mood changes per route. Next.js App Router structures the pages; the theme layer rides on top. The payoff is range without drift. Each route can take its mood somewhere new while still reading as the same site by the same hand.

  • Tailwind v4, CSS-first tokens — one source of truth
  • Day and night sakura variants from the same variables
  • Per-route themes, not per-route rewrites

Motion only where it earns its keep

Motion is choreographed in GSAP and ScrollTrigger, not sprinkled on. Scroll drives scene transitions; the work page pins into a horizontal slider; reveals stagger in as sections enter view. Loading isn't dead time either — themed liquid-glass loaders hold the frame while interactive Spline 3D scenes spin up as page heroes. Those scenes react to the cursor with distortion, so the hero feels handled rather than decorative. The rule throughout: every animation answers to the content. If a transition doesn't clarify where you are or where you're headed, it gets cut. That's the line between a site that moves and a site that's just busy.

  • Pinned horizontal work slider via ScrollTrigger
  • Cursor-reactive Spline 3D heroes
  • Liquid-glass loaders themed per page

Reduced-motion and no-JS are first-class paths

None of the motion is allowed to trap anyone. Every overlay has a no-JS escape hatch, navigation works from the keyboard, and a reduced-motion path runs throughout — not a stripped fallback, a deliberate alternate. The site also respects prefers-reduced-transparency, so the liquid-glass surfaces dial down for people who need them to. I treated accessibility as part of the design, not a compliance pass at the end. A motion-led site is exactly the kind that breaks for people on the edges, so the edges got designed first — alongside the showpiece interactions, not bolted on after them.

  • Reduced-motion paths as deliberate alternates
  • Keyboard-friendly navigation, no-JS escape hatches on every overlay
  • Respects prefers-reduced-transparency

I made every call; agents wrote the code

Honest scope: I designed this and directed AI coding agents (Claude Code) to build it. The architecture, the motion design, the theme system, and every taste call are mine — the agents typed under direction. That's how I work now, and it's the point, not a caveat. Directing the build well takes its own skill: holding the whole system in your head, specifying intent precisely, and rejecting output that's close-but-wrong. The design decisions are where the craft lives, and those didn't get delegated. What you're looking at is that loop made visible — me deciding, agents executing, me judging the result, then doing it again.

Credits
Solo — design & direction
AI
Designed the site and directed Claude Code to write the build — owning the architecture, motion design, theme system, and every taste call.
TypeScriptNext.jsReactTailwind CSSGSAPFigmaVisit

DL-002 · Desktop Automation

Deeds Leisure — Lead-Gen Tool

ShippedPython/AI Scraper & Sales InternJan – Mar 2026~75% TIME SAVED

Deeds Leisure — Lead-Gen Tool — view 1 of 3
Deeds Leisure — Lead-Gen Tool — view 2 of 3
Deeds Leisure — Lead-Gen Tool — view 3 of 3

Deeds Leisure's sales team prospected by hand — searching city by city, category by category, copying out contact details one search at a time. As a Python/AI scraper and sales intern, I built the tool that replaced that grind: a desktop app that researches outreach targets across 25 Ontario cities and 43 business categories on demand. The people running it weren't technical, so it had to feel like a product, not a script. I sat on the sales team it was built for, which kept the requirements honest and the test loop short.

I was a user of the tool I was building

My title had two halves — scraper and sales — and that turned out to be the point. I did the manual prospecting myself before I automated it, so I knew which steps were tedious and which fields the team actually used. Outreach research meant working through 25 Ontario cities and 43 business categories, one search at a time. Building for a team I sat on meant I could test a change at my own desk and watch whether it saved real minutes, not hypothetical ones. The estimated ~75% cut in prospecting time came from removing work I had personally felt.

  • Built the tool while doing the manual prospecting myself
  • ~75% less manual prospecting time (estimated)

A thousand lines of Python, no API to lean on

There was no clean data source to call, so the pipeline assembled one. Roughly a thousand lines of Python: DuckDuckGo Search to surface candidate businesses per city and category, BeautifulSoup to parse the pages it found, and regex to pull contact details out of messy HTML. Each city–category pair fanned out into its own search, then folded back into one lead list. Scraping is brittle by nature — layouts vary, pages break — so much of the work was the unglamorous part: handling the cases where extraction returned nothing useful and keeping the run moving instead of stalling on a bad page.

  • ~1,000-line pipeline: DuckDuckGo Search + BeautifulSoup + regex
  • Fan-out across 25 cities x 43 categories, merged into one list

Scoring kept the team from chasing dead ends

A raw scrape gives you volume, not quality — and a sales team that wastes calls on bad leads stops trusting the tool. So the pipeline scored every lead 0–100 instead of dumping everything it found. Franchises got filtered out, since national chains weren't the target. A domain blocklist caught directories, aggregators, and other noise that kept resurfacing. The point wasn't a perfect score; it was a list someone could work top-down with reasonable confidence. Ranking changed how the output got used — the team could trust the top of the list and stop second-guessing every row.

  • 0–100 lead quality scoring
  • Franchise filtering + domain blocklisting

The scraper only counted once someone could double-click it

A Python script is useless to a sales team that won't open a terminal. So I designed a frameless desktop UI in Figma and wrapped the pipeline in an Electron app, with Node bridging the interface to the Python underneath. Then I packaged it as a .dmg and .exe with PyInstaller and electron-builder, so installing it was a double-click on whatever machine someone had. That last mile taught me the most: the engineering was only as valuable as the moment a non-technical colleague could run it alone, without me on a call walking them through Python. Packaging was the feature.

  • Frameless desktop UI designed in Figma, wrapped in Electron
  • Shipped as .dmg and .exe via PyInstaller + electron-builder
Credits
Solo build, embedded on the sales team
PythonElectronNode.jsFigma

More from the catalogue ·

Also in the workshop.

Hardware and earlier client work — shorter to tell, but they shaped how I build.

  • Minoa Home — Shopify UX / SEO
    MN-0042024 – 2025

    Minoa Home

    Shopify UX / SEO

    A Shopify storefront audit and content system across B2B and B2C journeys for a sustainable-luxury brand.

    UX · SEO AUDITFigmaVisit
  • FM Radio Module — Embedded Systems
    FM-005

    FM Radio Module

    Embedded Systems

    A functional FM radio built from an Arduino Due and a TEA5756 module — tune stations, read the frequency live, and hear it through an amp and speaker.

    LIVE FM TUNINGC++ArduinoGitHubCode
  • Auto Plant Watering System — Arduino + MATLAB
    AW-006

    Auto Plant Watering System

    Arduino + MATLAB

    An Arduino + MATLAB rig that reads soil moisture and waters a plant automatically — only when the soil actually runs dry.

    AUTO-WATERS ON DRYArduino