Colophon
How This Site Is Built
The homepage is a Vue app. Everything else on the site is plain HTML generated from the same data when it's built. This is how the pieces fit together, and why some of them work the way they do.
One copy of every sentence
Nearly all the copy on the site lives in two data files with no imports, so Node can read them without a bundler. The Vue app renders the homepage from them. When the site is built, the same files produce the service pages, the case studies, the resume, the open source pages, the structured data, the sitemap, llms.txt, and a plain HTML copy of the homepage for crawlers that don't run JavaScript. There is one copy of each sentence, so none of those versions can disagree with another.
Pages without JavaScript
Only the homepage is an app. Every other page, this one included, is static HTML with its stylesheet inline and its two font files preloaded, so nothing has to run before you can read it. The one script on these pages is the Google tag. It loads asynchronously, and only production builds include it, so local and preview builds never report a visit.
Sitemap dates that mean something
Each page's date in the sitemap comes from a hash of its content, kept in a file that's committed with the site. Rebuilding a page without changing its text keeps its old date. If every page carries the date of the last deploy, search engines see every page change every time and soon stop trusting the date at all.
A real 404
Single-page apps are often hosted with a rule that answers every unknown address with the homepage. That returns a success code for pages that don't exist, and search engines end up indexing them. There's no such rule here, so an address that doesn't exist gets a 404 page with a 404 status.
The motion on the homepage
The scrolling and the scroll-driven animation run on GSAP. The fluid that follows your pointer and the particle field in the header are WebGL, through three.js, which is split into its own chunk so it isn't part of the main bundle. If your system asks for reduced motion, the fluid isn't loaded at all. When it is running, it stops solving once the dye has faded and nothing is moving, and starts again on the next frame the pointer moves.
One switch for looking for work
Everything on the site that says I'm available hangs off one flag. That covers the status in the header, the section above the contact details, the line at the end of each of these pages, and the homepage's share image. When I take a job, I change one line and all of it goes.
Built with
- Vue 3
- Vite
- Tailwind CSS
- SCSS
- GSAP
- three.js
- Firebase Hosting
Get in touch
I build the same way for clients. Tell me what you need.
I'm available now for full-time roles and contract work, remote or hybrid around Lakeland, Tampa and Orlando.