Hi, I’m Zack, aka BellCube

Full Stack Developer & Problem Solver

I solve complex problems elegantly and I do web development. Highly familiar with React and Next.js, but also highly flexible. Backend work, authentication, and API development are also firmly within my wheelhouse.

I’m always up for a challenge. I love creating intuitive, user-friendly applications. I love exposing data in new ways. I love building stuff people find genuinely useful.

I solve complex problems elegantly and I do web development. Highly familiar with React and Next.js, but also highly flexible. Backend work, authentication, and API development are also firmly within my wheelhouse.

I’m always up for a challenge. I love creating intuitive, user-friendly applications. I love exposing data in new ways. I love building stuff people find genuinely useful.

Technologies & Skills

A comprehensive overview of technical proficiencies with an honest ranking system. Each technology is ranked on a scale of 1-5, where 5 represents expert-level proficiency (in practical application) and 1 indicates basic implementation experience with minimal customization.

TypeScript
JavaScript
React icon
React
Sass icon
Sass
Linaria wordmark
CSS icon
CSS
ESLint wordmark
Next.js icon
Next.js wordmark
Discord.js wordmark
Prisma ORM icon
Prisma ORM
Zod icon
Zod
Node.js icon
Node.js
GitHub Actions icon
GitHub Actions
PNPM icon
PNPM
Docker Compose icon
Docker Compose
Passkeys icon
Passkeys
Vitest icon
Vitest
Vercel icon
Vercel
Cloudflare Compute (Workers) icon
Cloudflare Compute (Workers)
tRPC icon
tRPC
TanStack/React Query icon
TanStack/React Query
PostgreSQL icon
PostgreSQL
Drizzle ORM wordmark
Posthog wordmark
Supabase wordmark
Express.js icon
Express.js
Unified wordmark
(Framer) Motion icon
(Framer) Motion
Jest icon
Jest
Google Cloud icon
Google Cloud wordmark
Stripe wordmark
React Native icon
React Native
Expo SDK icon
Expo SDK
GraphQL icon
GraphQL
Docker wordmark
Docusaurus icon
Docusaurus
Hono icon
Hono

Projects. Projects everywhere.

No programmer is complete without a wealth of hobby projects to show off!

You Are Here!

This Portfolio Site

Monorepo project using a Next.js frontend and a heavily-customized headless CMS, both deployed to Cloudflare's Compute (Workers) platform.




Challenges and Takeaways

Blurs, Shadows, OpenGL Shaders, and Mobile Performance

I have a 6-year-old mid-range Android phone, which I feel is a fairly decent test for how well a website performs on consumer mobile hardware in the US. As I soon found out, my portfolio site—which was even heavier on blurs, shadows, and OpenGL shaders than it is now—performed quite poorly on said 6-year-old mid-range Android phone. This required careful tuning and debugging, trading marginal quality improvements for significant performance increases.

Turns out, you can't have all of the neat effects on your portfolio site.

Not Including My Real Name (but still showing it if you click a link from my private resume)

If you navigated to this site by clicking one of the links in my resume PDF or my LinkedIn page, you've been seeing my full, real name this entire time. If you navigated here by any other means (e.g. by typing it in directly), you don't see my real name! A simple effort to not blatantly dox myself.

This is accomplished through a query parameter called realName, with first and last deliniated by a semicolon. This parameter is validated at request time to see if it matches a salted hash. If it does, it's allowed through—otherwise, it'll throw you to a HTTP Status 400 page. For example, try https://bellcube.dev/?realName=John;Doe.

Hero Blurhash at Build Time

Ah, Next.js. Infamous for its lack of ability to control what happens when/where (though it should be fixing a lot of those issues in v16 👀). To massively improve percieved loading performance, I decided to render a CSS-based blurhash for the hero image. This works great, except—

  • Generating this blurhash takes somewhere around 30–80 seconds, so it can't be done at request time
  • Next.js' unstable_cache function doesn't seem to run at build time; only on the first request, even with { revalidate: false}
  • Importing the sharp library at all (needed to parse the image into raw pixel data for the blurhash library) from any Cloudflare Worker code is a no-go

This meant I needed to inject assets before building. Easy enough to write a script to do it and to cache it for CI builds.

Misc. Challenges

  • Debugging a few SSR hydration mismatch issues
  • Creating this very masonry-style project card layout (no JS, no predefined sizes)
  • Making the effects from React Bits more reliable and suitable to my tastes
  • Optimizing the first-load experience

On the Usefulness of AI Code Generation

As I was starting the codebase for this portfolio site, automated AI tooling was a large help in scaffolding the website, generating a coherent layout, and implementing the basic design I was looking for. However, further use of AI lead to significant fragmentation of the codebase, particularly in the CMS portion (which was forked from an already poor-quality codebase). Through this, I've learned that AI code generation should, for the time being, be largely limited to scaffolding/boilerplate and simple, repetative changes.

Simple Minesweeper

Simple Minesweeper

Nothing complicated; just Minesweeper. It's quick, it's dirty, but it's highly functional. It helps demonstrate that:

  • I can solve problems algorithmically, rather than jumping for the most obvious (and possibly expensive) solution.
    • One random number is rolled per mine. Mines cannot be placed where other mines exist and cannot be placed on or in a tile adjacent to the first click. This is handled algorithmically rather than simply requesting a new random number when the old is invalid.
  • I can solve problems quickly and efficiently
  • I am not tied down to a specific ecosystem (e.g. React's ecosystem)
  • I can adjust my approach when necessary



Challenges and Takeaways

  • I initially intended to use React, however doing so with the state tree as I envisioned existed would have been more complexity than it was worth. React is not designed for highly-optimized, mutable, game-like state structures.
  • I made the decision to drop React mid-development, after I'd already implemented a basic UI (glued together with my Immer fork), which was a good call.
  • Built entirely without AI tools (e.g. line completion). Partially because I wanted to do it without AI, and partially because I knew that I was writing tightly-integrated code with no room for mistakes.
the Papyrus Index

the Papyrus Index

The first searchable index for modder-added extensions to the Papyrus scripting language, used for Bethesda games like Skyrim and Fallout. Also the first searchable index for any Papyrus information with data generated directly from source code!

The Papyrus Index boasts:

  • Automated extraction of key information from Papyrus Source Code (.psc) files, ensuring complete accuracy to what developers can actually use
  • Fuzzy text searching across (currently just) Scripts and Functions, handled client-side
    • Search being handled client-side lets this be a static website! The largest (lazy-loaded) search index at the moment is less than 0.75 MB over the network.
  • Helpful tooltips and syntax demonstrations act as a quick reference and help Papyrus learners understand each page
  • Automatic documentation aggregation/scraping from multiple sources, including:
    • Comments in the source code
    • Documentation strings in the source code (these are separate from comments in Papyrus)
    • A couple of MediaWiki-based wikis
    • A few GitHub Wikis
  • Online reference for 45 different sources of developer-facing Papyrus functions across 3 games. Since each game comes with built-in Papyrus functioanlity, 42 of those 45 sources are mods that extend the functionality of the language in some way
    • The Papyrus Index is the ONLY resource to aggregate more than 5 sources!

The data exists in the backend to also display and search across Events, Structs, and Properties, however these features have not yet been implemented in the frontend.




Challenges and Takeaways

Contacting UESP Wiki Maintainers

The Papyrus Index pulls information automatically from established community wikis. However, this data fetching results in thousands of requests for the wiki to handle. Additionally, the wikis were using Cloudflare, which did not allow any WikiMedia API requests through at all.

The project therefore required contacting the maintainers of the Unofficial Elder Scrolls Pages (who host some of the wikis the Papyrus Index pulls data from) in order to resolve Cloudflare issues and establish reasonable throttling that works for the UESP team.

Parsing MediaWiki Content

WikiText, in the context of a larger MediaWiki instance, is an incredibly difficult format to parse on your own, if you wish to do so accurately. The format comes with reusable templates, page categories that can appear anywhere in the page, and other complicating factors for efficient data extraction. Luckily, MediaWiki has a service called Parsoid (used for the visual editor) that can be used to turn raw WikiText into an HTML document, which is much more suitable for automated data extraction.

However, Parsoid, when run behind a MediaWiki instance and dealing with hundreds of requests, is highly unreliable. Frequent crashes and timeouts are expected. It was therefore more optimal to run Parsoid locally. Parsoid is a PHP project using Composer for its package manager, which was interesting to get set up in a way that it could be easily invoked by a static Next.js website codebase.

Non-representative Code Quality
Additional Clockwork

Additional Clockwork

Additional Clockwork seeks to improve the Clockwork mod for Skyrim. It is a collection of individually-selectable tweaks, such as:

  • General bug fixes, including a number of bugs as old as the mod itself
  • Dynamic item sorting,replacing the hardcoded list method used by the original mod, which did not sort any mod-added items)
  • Removing the giant, possibly immersion-breaking mod title that appears when first discovering the Clockwork Castle location
  • Adding certain in-game symbols associated with a faction the player can join (the Thieves Guild). The symbols are not visible until the faction would normally add them.
  • Adding a wall mount for a woodcutter's axe.
  • A special version of my other mod, Woodworker's Whim, which is only enabled within the reaches of Clockwork Castle



Challenges and Takeaways

As one of my earliest serious projects, Additional Clockwork suffered from impressive levels of scope creep. Experience is the best teacher, and I certainly learned to scope my projects down after working on Additional Clockwork.

full-uri-escaper

full-uri-escaper

Not much more to say, really.

You know how, in a URL, to have a space, it needs to be escaped as %20? Imagine that, but for every character of a string.

import fullURIEscaper from 'full-uri-escaper';

// Set `escaped` to
console.log( fullURIEscaper('Whatever you say, Mr. Boss-man!') );

Output:

%57%68%61%74%65%76%65%72%20%79%6f%75%20%73%61%79%2c%20%4d%72%2e%20%42%6f%73%73%2d%6d%61%6e%21

@bellcubedev/immer

A fork of Immer to support multiple references to the same object within an immutable tree.

Immer is an immutability library designed to take advantage of native JavaScriptfeatures to allow for immutable trees that feel native. The tree cannot be mutated normally, but creating a new copy of the tree is as simple as mutating the tree within their produce(recipeFn) function. Very clean and developer-friendly, but, as a caveat, stock Immer does not support having multiple references to the same object within your immutable tree.

I, however, needed it for use with the Fomod library (also in the projects list). So I built it and submitted a PR to Immer. The PR has yet to be reviewed, but the fork is available on NPM and has served me well!




Challenges and Takeaways

Immer is a complex library with deeply-intertwined inner workings. Even understanding the data structure behind Immer was a chore, and my initial instinct was to try and hack something into it as quickly as possible.

For a project as tightly-integrated as Immer, though, such hackery turned quite problematic. After numerous attempts to salvage my hack-like attempt, I eventually resolved to start from scratch, truly understand Immer's model, and—importantly—run my new implementation against Immer's existing unit tests. Implementing multi-reference support for Immer significantly strengthened my understanding of the importance of testing, and similarly taught me to slow down and understand a codebase before attempting to modify it.

fomod Library

Fomod installers are a common XML format used by various mod managers for video games (especially Bethesda games). fomod is the first (and, to my knowledge, only) JavaScript/TypeScript library that abstracts Fomod installer definitions beyond simple XML and returns them as native JavaScript classes.

The library:

  • Was designed with both reading and writing in mind
  • Includes certain safety checks at multiple levels to prevent common errors
  • Is end-to-end tested, including with large, real-world Fomods (one of them is over 30,000 lines long)
  • Includes snapshot tests in its repo to ensure the output behavior does not change unexpectedly
  • Implements the entire Fomod spec and exposes its full range of customization options
  • Prioritizes in-place editing wherever valid. When possible, state is serialized to an existing DOM. Fully supports creating new DOMs (even with existing installers; useful to ensure spec compliance).
  • Enhances developer experience by simplifying the Fomod API where possible (while still retaining full, low-level, in-spec control)
  • Can parse and understand invalid data while remaining transparent to the developer
  • Enforces strong typing by default (e.g. "Ascending" | "Descending" | "Explicit") and allows for weak typing (e.g. string) for cases such as user-submitted installers
  • Includes built-in validation so developers can easily check if a user-submitted installer is valid and provide specific error messages. Validation doubles as a predicate for strong typing.
  • Includes useful abstractions for developers working on Fomods. These abstractions are optional, can be both serialized and parsed, and can be adopted incrementally—allowing developers to opt into more abstract behavior while retaining low-level control where necessary/desired.
  • Allows for automatic optimization for installers. While lossy, these optimizations can improve performance and clean up redundancies in installers that aren't following best practices.



Challenges and Takeaways

  • Dealt with numerous hard-to-spot issues, especially missing logic required by the spec and incorrect string literals. These were resolved by:
    • Introducing end-to-end contract testing
    • Migrating literals to enum values, and introducing automated testing of literals against the XML schema
  • It is important to find the right data structure for an abstraction. Paper/Excalidraw helps a lot with this.
Woodworker's Whim

Woodworker's Whim

In Skyrim, the player has the opportunity to interact with various resource-producing objects, such as wood chopping blocks and ore veins. In order to interact with one of these objects, however, you must have the appropriate tool—in this case, a pickaxe for an ore vein and a woodcutter's axe for a wood chopping block. But, it's often impractical to carry one!

Enter Woodworker's Whim. Now, when interacting with a compatible workstation, the player will automatically search the nearby area for a compatible tool, borrow it, and return it once done using the workstation.




Challenges and Takeaways

Woodworker's Whim dealt largely with concurrency issues. Papyrus is a highly-multithreaded language that can be started and stopped by the game at a moment's notice. Combine that with an open world game and, suddenly, a lot of edge cases can occur.

Safe error detection and recovery was crucial to this project's success.

Zane Stat Calculator

Zane Stat Calculator

A game designer by the name Zane created a tabletop RPG with a fairly unique leveling system designed for long-term playability. The problem was, this leveling system was incredibly tedious to apply to lots of high-level NPCs (lots of random numbers and lots of carries-over-to-the-lext-level data). He asked me to build a tool he had mocked up, and I got to work.

The calcualtor, to this day, serves Zane incredibly well and passively sped up his NPC creation workflow. The process of creating it demonstrates my ability to quickly prototype and deliver non-user-facing products without worrying about unimportant factors for behind-the-scenes interfaces. The project:

  • Required strict adherence to loosely-worded specifications
  • Saves data in a manually-editable YAML format and respects manual edits wherever possible. This gives the user full control when they need it.
  • Required integrating feedback from the requesting party, significantly improving the tool in the process
  • Was intended to be quick-to-implement, and intelligent tradeoffs were made to speed up the process
    • An opinionated, off-the-shelf component library was chosen to speed up development
    • Rendering performance was only addressed when it became a noticable issue. Typically when writing a component, I spend significant time considering component optimization.
    • Code was simply copied, pasted, and modified in certain areas where abstractions would normally be used, rather than spend additional time developing the addequete abstractions. This was sped up by using AI to perform the duplication and modification while I worked on other parts of the codebase.
  • Nonetheless includes useful features not specifically requested, like reverting changes before they are applied



Challenges and Takeaways

  • Performance became an issue once the interface got larger. This required React optimization techniques like splitting monolithic components into smaller ones.
  • The specifications given for the project were not always clear and were written under the impression that the implementer was already familiar with the process. This required frequent and careful re-reading of the requirements.
  • It is OK to sacrafice some performance and maintainability goals in favor of development speed, especially when it comes to internal-use utilities.