I build products for the web and the parts underneath that keep them fast. These days that means a React and TypeScript front end, Python services on Azure, and being fairly opinionated about the pipeline in between.
- An enterprise SaaS platform for consumer research. React 18 and TypeScript on the surface, Python and FastAPI services on Azure behind it. Canvas-based design annotation, embedded analytics, AI-assisted content generation.
- A design system people actually follow. Semantic tokens over palette steps, Storybook for every primitive, and a CI guardrail that fails the build on a hardcoded hex rather than leaving it to review.
- Spec-driven, agent-assisted delivery. Behaviour contracts written before the code, trunk-based shipping so every commit is releasable, and agents doing the work that should not need a human.
| Frontend |
|
| Backend |
|
| Platform |
|
Core team at ReactJS Philippines and a moderator of the community group. If you are learning React in the Philippines, come say hello. Nobody there will make you feel bad for asking a beginner question.
Goal: help make the world a better place before I die.
Not just people stuff. The whole animal kingdom and nature too.
How this README is built
The banner, the terminal, the stats card and the footer are not screenshots and
they are not hosted card services. They are SVGs generated by
scripts/build-assets.mjs and
scripts/build-stats.mjs, then committed to this repo.
That last one is the point. The popular hosted stats card is one shared
deployment that answers 503 often enough to leave a profile visibly broken, so
this queries the GitHub GraphQL API directly, renders the numbers in the same
palette as everything else, and lets a scheduled
workflow commit the refreshed file each day.
A few constraints shaped them, because GitHub serves README images through its
camo proxy inside an <img> tag:
- No external fonts, stylesheets or scripts. System font stacks only, with caret and column positions computed from the monospace advance width so they land in the same place on every platform.
- CSS animations and SMIL both run, JavaScript does not. The typing effect is a
clip rectangle stepping through discrete widths; the orbits are
animateMotionalong paths in<defs>. - GitHub does not tell the image which theme is active, so each asset ships in a
light and a dark variant, paired with
<picture media="(prefers-color-scheme)">. One generator emits both, so a palette change cannot desync them.
Regenerate with node scripts/build-assets.mjs, then bump the ?v= query on the
image URLs so camo re-fetches.




