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.
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
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.
CONTENTS
01 BACKGROUND
02 MY ROLE
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.
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.
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.
FIG. 03 — Project overview
CONTENTS
03 ONE DATA HOOK, THREE SOURCES
04 A CONTENT SCHEMA FOR NON-DEVELOPERS
05 SMALL CUSTOM INTERACTIONS
06 OUTCOME
07 LESSONS LEARNED
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.

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.

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.

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.

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.