03
ALL WORK
03

CONTENT PLATFORM · 2024–PRESENT

GA TCG Sandbox Site

Marketing and documentation site for a Unity-based digital sandbox tool for the Grand Archive TCG — downloads, patch notes, and a structured feature guide, all content-driven from a GCS bucket the client team owns directly. My scope was the site, not the Unity application.

ReactTypeScriptViteTailwind CSSGoogle Cloud Storage

3

GCS-BACKED CONTENT SOURCES

19

FEATURE GUIDE ENTRIES

0

DEPLOYS TO UPDATE CONTENT

1

DEVELOPER (ME)

MY CONTRIBUTION

Frontend Development

Led

Architecture Design

Led

Content Modeling

Led

Client Handoff

Led

Led
Collaborated
Supported

BEFORE / AFTER

BEFORE

No existing site. The client team could build and release a Unity application but had no web tooling familiarity — any content workflow that needed a developer for routine updates (a new patch note, a download link change, a feature guide edit) was going to create friction that wouldn't hold up release after release.

AFTER

A single React app where every piece of dynamic content — site config, patch notes, the feature guide — loads from JSON files in a GCS bucket at runtime. The client uploads a new file to the bucket; the change is live on next load. No PR, no deploy, for any of it.

01

Background

The Grand Archive TCG needed a site for their Unity-based digital sandbox tool — a way for players to download an installer, follow setup instructions, read patch notes as updates shipped, and look up how specific in-app features work. The client team was small and non-technical on the web side. They knew how to build and release a Unity application; they did not know how to open a PR or trigger a deployment. Any content workflow that required developer involvement for routine updates was going to create friction that wouldn't hold up over time.

02

My Role

I was the sole developer on the website — not the Unity application itself. That distinction matters: the sandbox tool is a separate binary that the client team builds and distributes. My scope was the site that wraps it. Full-cycle freelance delivery: requirements gathering with a small external team, architecture, implementation, and handoff documentation. The client needed to own the site's entire content workflow after I was done, not just part of it.

KEY DECISION

One uniform content path, not a special case per content type

DECISION

Every piece of dynamic content — site config, patch notes, and the feature guide — is fetched from GCS through the same hook, in parallel, with identical fallback behavior. Nothing gets a different update path just because it changes on a different cadence.

REASONING

It would have been easy to treat these differently: patch notes change every release, the feature guide changes rarely, site config almost never. Giving each its own ownership model — some in the repo, some in the bucket — would have been defensible on paper. I didn't do that, on purpose. The client team's entire mental model for "updating the site" needed to be one motion: upload a file to the bucket. Teaching one workflow that applies uniformly to everything they might ever need to touch was worth more than any efficiency gained from optimizing per content type. Six months from now, updating the feature guide is the identical motion to this week's patch note.

GA TCG Sandbox site home page — "Grand Archive Sandbox, Alpha Early Access" panel over a blurred in-app board background, with a Download Sandbox CTA

FIG. 03 — Project overview

03

One Data Hook, Three Sources

A single useAppConfig hook is the only place the app talks to GCS. On mount it fires three fetches in parallel — site config, the current patch note, and the feature guide — and merges the results into one typed config object once all three resolve. If any fetch fails, the whole hook falls back together to bundled local copies of the same three files, shipped in the app itself. A network hiccup, a bucket misconfiguration, a malformed upload — none of it blanks the page. The site quietly serves the last-known-good bundled state instead, and nothing downstream has to know the difference.

News page rendering the current patch note pulled from GCS — "Sandbox Update Notes - Version 0.1.5," dated April 27, 2026, with New Features and Bug Fixes lists
Patch notes rendered from the same GCS fetch path as site config and the feature guide — no special-cased content type
04

A Content Schema for Non-Developers

The feature guide is the most structurally interesting piece: 19 entries across five categories, each entry a small tree of content blocks — plain text, bullet lists, or titled subsections that can themselves hold text and ordered lists. A category-tabbed browser on the page reads that structure directly and renders whichever combination a given entry needs. Designing that schema was the real content-modeling work. It has to be expressive enough that a non-trivial "how do I do X" explanation doesn't get flattened into an unreadable wall of text, but constrained enough that someone editing raw JSON in a bucket can't produce a shape the renderer doesn't know how to handle. Three block types turned out to be enough range for the whole guide without ever needing a fourth.

Guide page showing the category-tabbed feature browser open to "Getting Started > Starting a Game Room," rendering nested Setup, Hosting a room, and Joining a room subsections from the JSON content schema
One feature guide entry — a titled subsection tree rendered from the same three-block-type schema as the other 18
05

Small Custom Interactions

A handful of details are hand-rolled rather than pulled from a library. Section navigation uses a custom requestAnimationFrame loop with eased timing instead of native smooth-scroll, so the duration and feel are controllable rather than left to the browser. Section content fades in via a small IntersectionObserver-based hook rather than a scroll-animation library. The download button has a looping shimmer sweep built from a single absolutely-positioned gradient div and a CSS keyframe — no canvas, no animation dependency. None of these are complicated in isolation. They're the kind of detail that's easy to reach for a library on and just as easy to hand-roll once you notice the library would be doing less work than the code to configure it.

Download page with a two-step install guide — "Download the game build and run gatcg_sandbox_installer.exe" and "Press the login button to sign in with your Omnidex" — and the shimmer-sweep Download Sandbox button in the header
The download flow — home to the hand-rolled shimmer CTA referenced above
06

Outcome

The client team publishes patch notes, updates download links, and edits the feature guide on their own schedule without filing a ticket or waiting on a developer — the same upload-a-file motion covers all three. The site has stayed live and current through the sandbox tool's ongoing open-testing phase without a single content-driven deploy. Repo is private (client project). Code available on request.

Footer "Get Involved" section with Submit Feedback and Join Sandbox Discord buttons alongside social links, during the open-testing phase
The feedback loop the client uses during open testing — no developer in the path
07

Lessons Learned

Treating patch notes, config, and the feature guide identically — same hook, same fetch pattern, same fallback — was a small discipline that paid off more than expected. It would have been easy to special-case the feature guide as "this one's basically static, just import it," since it changes far less often than patch notes. Keeping it on the exact same GCS path as everything else meant the client never had to remember which content type worked which way, and I never had to maintain two different update mechanisms for what is, from the user's side, the same kind of task.