The Arthis.Land
Website Reference.
A complete technical and design reference for the Arthis.Land website — every page, every component, every animation, every visual rule. No credentials, no private data. Pure architecture.
01Product Overview
Arthis.Land is a vertical-city / room-maker experience. The website is the storefront and lobby for the experience: it lets visitors discover the project, see the wall of community rooms ("games"), watch the city tower fill up, download the desktop build, and join a waitlist for the live drops.
The site is built as a multi-page static site (plain HTML files at root) with one heavy interactive React page (the Wall) and an embedded Unity WebGL build (the City viewer). It uses no bundler at runtime — React is loaded from a CDN and JSX is compiled in the browser by Babel Standalone. The development workflow uses Vite.
Visual identity in one line: brutalist red
#E11D1Don near-black or off-white, retro pixel-display typography (Jersey 10 / Jersey 20), mono-spaced micro-labels (JetBrains Mono), with crisp 1px borders, hex / brick grids, vignettes, grain overlays, and clipped-corner buttons.
02Site Map
The site is structured as five primary surfaces plus an interactive React-driven sandbox folder used for design iteration.
| Route | File | Purpose |
|---|---|---|
/ | index.html | The Wall — interactive 900-brick gallery of rooms/games. |
/about.html | about.html | Marketing page: hero, stats, how it works, drop countdown, features, CTA, download. |
/download.html | download.html | Dedicated download page with OS buttons and waitlist modal. |
/documentation | documentation/index.html | This page — technical and design reference. |
/city/ | city/index.html | The City — embeds a Unity WebGL viewer inside an iframe with a loading veil. |
/city/viewer/ | city/viewer/index.html | Bare Unity WebGL host (loader.js + canvas). |
/Arthis.Land (Remix)/ | dev sandbox | A duplicate of the Wall code used for live design tweaks via a floating tweaks panel. |
Cross-page navigation is light — the footer on download.html links to About, The Wall,
and City. The Wall page itself is intentionally chrome-free aside from the logo bubble.
03Tech Stack
The runtime stack is deliberately minimal so the site can be hosted as plain static files.
- HTML5 / CSS3 — no preprocessor, vanilla CSS with CSS custom properties (variables) for theming.
- React 18.3.1 — loaded as a UMD CDN bundle (
react.development.js+react-dom.development.js). - Babel Standalone 7.29 — compiles
<script type="text/babel">JSX in the browser. No build step required for the Wall. - Supabase JS client (UMD) — for the room/game data layer and waitlist persistence on the Wall.
- Unity WebGL build —
.loader.js,.data.gz,.framework.js.gz,.wasm.gz, streamed from/city/viewer/Build/. Lives inside an iframe. - Vite ^5.4 — dev server only (
npm run dev). - HTML5 Canvas API — used for two ambient background effects: the animated hex-grid on
/download.html, and the particle field on/about.html. - Google Fonts: Inter, JetBrains Mono, Jersey 10, Jersey 20, Jersey 20 Charted, Press Start 2P.
- Custom font (self-hosted):
Jersey10-Regular.ttf(underAssets made/).
No framework router, no SSR, no service worker. Pages are independent HTML documents that share the same asset folder.
04File & Folder Structure
Main index/ ├── index.html ← The Wall (entry point) ├── about.html ← Marketing/about page ├── download.html ← Download + waitlist page ├── documentation/ ← This documentation site ├── package.json ← Vite dev script only ├── app.jsx ← React app for the Wall ├── tweaks-panel.jsx ← Floating dev tweaks panel ├── brick-data.js ← Procedural brick generator ├── styles.css ← Wall stylesheet ├── supabase-client.js ← Data client │ ├── assets/ │ ├── arthis-logo.png │ ├── LOGO-3Edited.png │ ├── Design metaverse.png │ ├── logo-splash-bottom.png │ ├── logo-splash-center.png │ └── loop.mp4 │ ├── Assets made/ │ └── Jersey10-Regular.ttf │ ├── city/ │ ├── index.html │ └── viewer/ │ ├── index.html │ ├── Build/ │ └── StreamingAssets/ │ └── Arthis.Land (Remix)/ ← Dev sandbox copy of the Wall
The duplicated Arthis.Land (Remix)/ folder mirrors the production Wall so a
designer can hot-tweak the layout via the in-page tweaks panel without affecting the
live root files.
05Design System
5.1Color Tokens
The site has two color worlds — the dark world (Wall, Download, City) and the light world (About, Documentation).
Dark world (Wall) — four theme presets
| Theme | Accent | Background | Panel BG | Text |
|---|---|---|---|---|
| Ember (default) | #ff3a2a | #0a0807 | #141110 | #f5e8e2 |
| Ash | #e8e2d8 | #0a0a0a | #161616 | #f0ece4 |
| Rust | #d96a3a | #0c0805 | #1a120c | #f0d9c8 |
| Ink | #ff2d2d | #050507 | #0e0e14 | #e8e8f0 |
Light world (About / Docs) — swatches
A single conceptual --accent variable is threaded through every interactive
surface; swapping it instantly re-skins buttons, focus rings, glow halos, and cursor outlines.
5.2Typography
The typographic system layers three voices:
- Display — pixel/retro.
Jersey 10andJersey 20for poster-scale headlines (DOWNLOAD, hero titles, modal "Almost there."). They lean nostalgic / arcade. - Body — humanist sans.
Interat weights 300–900 carries paragraphs, lede copy, button names, stats. - Micro / utility — monospaced.
JetBrains Monofor eyebrows, version chips (/ V 2.4.1), tags, coordinates, kbd shortcuts, metadata rows. Always uppercase withletter-spacing: 0.18em–0.32em.
Display sizes use clamp(min, fluid, max) for responsive scaling — e.g. clamp(80px, 12vw, 196px) on the download title.
5.3Spatial / Layout Rules
- The Wall uses absolute positioning (
position: absolute) on every brick. The whole stage is a fixed-viewport surface (position: fixed; inset: 0). - Marketing sections use
padding: 100px 40pxwith amax-width: 1100pxcontent column centered horizontally. - Buttons get a clipped-corner polygon (
clip-path: polygon(8px 0%, 100% 0%, calc(100% - 8px) 100%, 0% 100%)) on the primary CTA, giving the brutalist parallelogram look. - Borders are always
1pxor0.5px— crisp hairlines on high-DPI displays. - Backdrop blur applied to floating cards (
backdrop-filter: blur(12px)) over the dark world.
5.4Iconography
All icons are inline SVGs — no external icon library. Conventions:
- Stroke icons use
stroke-width: 2,stroke-linecap: round,stroke-linejoin: round. - Filled icons (play triangle, Windows tile, Apple silhouette) use
fill: currentColorso they inherit context color. - The custom cursor on the Wall is a hand-built pixel-art SVG arrow at 16×16 px, rotated to face the pan direction.
5.5Motion Tokens
A small set of easings and durations recurs across the site:
- Snap pop —
cubic-bezier(0.2, 0.8, 0.2, 1)at180–380ms. Hover lift, focus ring, modal entry. - Smooth zoom —
cubic-bezier(0.2, 0.8, 0.2, 1)at500–700ms. Wall tween-to-center and zoom transition. - Ease-out cubic —
1 - Math.pow(1 - t, 3). The hand-rolled tween insideapp.jsx. - Header drop —
cubic-bezier(0.25, 0.46, 0.45, 0.94)at380ms. Used in/city/. - Background ambient —
8s linear infinitefor the rotating cursor ring;20s linear infinitefor the grid drift on About.
06The Wall — index.html
The Wall is the landing experience. It renders a 900-brick mosaic in running-bond pattern (every other row offset by half a brick width) and lets the user navigate it without scrolling.
Document structure
<head> <!-- OpenGraph for sharing, favicon, Google Fonts --> <link rel="stylesheet" href="styles.css?v=7"> <style>/* per-page brick tint overrides */</style> </head> <body> <div id="root"></div> <script src="react.development.js"></script> <script src="react-dom.development.js"></script> <script src="babel.min.js"></script> <script src="supabase.min.js"></script> <script src="supabase-client.js"></script> <script src="brick-data.js"></script> <script type="text/babel" src="tweaks-panel.jsx"></script> <script type="text/babel" src="app.jsx"></script> </body>
Script loading order matters: Supabase and the data file must execute before the React app mounts because app.jsx reads window.ARTHIS_DATA.
Behaviour
The Wall does not scroll. Instead, the cursor's distance from the center of the viewport drives a continuous pan velocity in the opposite direction — moving the mouse right reveals bricks to the right because the wall translates left. A central deadzone (default radius 60px, configurable 0–200) freezes panning so the user can rest the cursor.
Clicking a brick:
- Sets
focusedIdto that brick's id. - Triggers a 700ms cubic-eased tween that translates the wall so the brick lands at screen center (or off-center left to make room for the detail panel on desktop).
- Scales the wall by
1.5×from origin(0,0). - Animates the brick's outline to the accent color and adds a glow shadow.
- Marks geometrically adjacent bricks as
--adjacentso they get a subtler highlight. - Slides in the detail panel (
<DetailPanel>) from the right.
Clicking the brick again, clicking off-brick, or pressing Escape un-focuses and resets the wall scale to 1×. On touch devices the cursor-pan loop is replaced by classic drag-to-pan via pointerdown / pointermove / pointerup.
Pan clamping
The function clampPan() ensures the scaled wall edges always touch the viewport edges —
no black gap can appear past the bricks. If the wall is smaller than the stage, it is centered;
otherwise pan range is [stageW - scaledW, 0].
Components inside app.jsx
| Component | Job |
|---|---|
App | Root. Owns pan state, focus state, cursor state, RAF loop, touch handlers, and the tween. |
Brick | One absolutely-positioned <button> with thumbnail, gradient shade, title, category chip, and pill-shaped PLAY button. Renders a blank decor brick when brick.blank is true. |
DetailPanel | Fixed-position 380px-wide card on the right with hero art, category & year, title, stats (rating, plays, id), description, primary "PLAY NOW" + ghost "+ WISHLIST" buttons. On mobile docks as a bottom sheet. |
PixelArrow | Custom cursor — a rotating dashed ring whose size scales with pan intensity, plus a pixel-art arrow SVG rotated to face the motion. Hidden when a brick is focused. |
TweaksPanel | Bottom-right floating dev panel exposed only when the host activates it. |
Visible-brick culling uses a 240px padding around the viewport: only bricks whose
bounding box intersects [-pad, stageW + pad] × [-pad, stageH + pad] are rendered.
Keeps DOM size bounded regardless of pan position.
Tweakable parameters (live, via the floating panel)
theme— radio: ember / ash / rust / inkvignette— slider 0–100 (radial darkness mask intensity)scrollSpeed— slider 4–30deadzone— slider 0–200 (px radius of the center freeze zone)showLabels— toggle (hides brick titles, categories, play badges)
These are persisted via a postMessage protocol (__edit_mode_set_keys) handled by
the parent host; the defaults are written between /*EDITMODE-BEGIN*/ … /*EDITMODE-END*/
comments in app.jsx.
07Procedural Wall Data — brick-data.js
The wall is not authored brick-by-brick. It is procedurally generated each load by
buildBricks(), which is then exposed at window.ARTHIS_DATA.
Generation algorithm
- Define a deterministic PRNG:
mulberry32(seed)returns a function producing repeatable floats in[0, 1). - Pick a vocabulary of 80 evocative two-word titles ("Crimson Gambit", "Hollow Reach", "Iron Lullaby"…) and 15 categories (
ADVENTURE,PUZZLE,ARCADE,STRATEGY…). - Loop over 60 rows. Each row picks brick widths from
[180, 220, 260, 300, 340, 380, 440]until the row hits target width. Every other row starts at offset-130to create the running-bond pattern. - For each brick, compute deterministic metadata from its id:
hue,year(2018–2026),rating(3.2–5.0),plays(1k–100k),title,category. - Generate a thumbnail SVG as a
data:URI: diagonal linear gradient between two HSL stops, an abstract motif chosen from {rising sun arc, triangle range, vertical stripes, concentric rings, diagonal slash}, an SVG turbulence noise layer atopacity 0.4, and a 2-letter monogram glyph atopacity 0.18. - After the real bricks, add a 3-brick-deep "ring" of
blank: truedecor bricks all around so the edge dissolves into pattern rather than ending abruptly. - Normalize coordinates so the wall starts at
(0, 0)and return{ bricks, bounds }.
The procedural approach means no API call is needed to render the wall, the layout is stable across refreshes, and the visual diversity is essentially free.
08Wall Stylesheet — styles.css
The stylesheet is organized in labeled sections, top to bottom:
:root— base CSS variables (--accent,--bg,--panel-bg,--text,--muted).- Globals — reset, body, font stack:
"Inter", system-ui, "Segoe UI", sans-serif. - Blank bricks —
.brick--blankwith double inset shadow, diagonal 2px-stripe pattern at 4% opacity, and a soft radial highlight in the upper-left. - Stage — fixed viewport,
cursor: noneon desktop (custom pixel arrow replaces OS cursor),cursor: defaulton mobile. - Bricks —
border-radius: 2px, inset top/bottom highlights and shadows to create a physical brick edge; hover lifts by-2pxand shows a 6px drop shadow + 1px white edge. - Focused brick — outlined in 2px accent, with a
0 0 24pxaccent glow and a heavy0 12px 40pxdrop shadow. - Brick face elements:
.brick__thumb,.brick__shade,.brick__title,.brick__cat,.brick__play. - Vignette — radial-gradient darkening from center.
- Crosshair / Deadzone — faint dashed reticle markers (z-index 21–22).
- Pixel cursor —
.pix-cursor__ring(rotating dashed circle,ringSpin 8s linear infinite),.pix-cursor__arrow(drop-shadow filter in accent). - Chrome overlays —
.chrome--logo,.chrome--hint,.chrome--coords. - Detail panel — 380px right-docked card, slides in with
detailInkeyframes. - Mobile —
@media (max-width: 720px)collapses chrome, drops cursor to OS default, docks detail panel as a bottom sheet.
09Tweaks Panel — tweaks-panel.jsx
A reusable floating panel — a tiny on-canvas design system editor — used to let a designer tune live values without rebuilding.
What it provides
useTweaks(defaults)— a hook that holds current tweak values and persists every change viawindow.parent.postMessage({ type: '__edit_mode_set_keys', edits }).<TweaksPanel>— a draggable, frosted-glass card pinned bottom-right (clamped on resize).- A control library:
<TweakSection>,<TweakSlider>,<TweakToggle>,<TweakRadio>,<TweakSelect>,<TweakText>,<TweakNumber>,<TweakColor>,<TweakButton>.
Host protocol
The panel listens for __activate_edit_mode / __deactivate_edit_mode from
window.parent, posts __edit_mode_available on mount, and posts
__edit_mode_dismissed when closed. This lets a parent host toggle the panel
in sync with its own toolbar.
Visual design
Frosted glass: rgba(250,249,247,0.78) background, backdrop-filter: blur(24px) saturate(160%),
0.5px translucent border, soft inset highlight, 14px radius, 280px wide, drag-by-header
to move. Form controls are 26px tall, 7px radius, 0.5px borders. Sliders are 4px tall
with 14px white circular thumbs and crisp inset shadows.
10Marketing — about.html
A single long-scroll marketing page. Distinct sections, animated on scroll, each with its own visual treatment.
Section list (top to bottom)
#hero— Full-viewport hero, off-white background, with a<canvas>ambient particle field, a subtle drifting red CSS grid, a floating 120×120 logo, a pulsing red badge pill, hero title with blinking dot, two CTAs (parallelogram red primary + ghost), and a scroll hint.#stats— Horizontal four-column stat bar with red separators. 2.5rem red numerics, 0.8rem letter-spaced gray labels.#how— Saturated red#E11D1Dbackground. Two-column grid: a 4-step list (Watch the Drop → Claim → Build → Explore) and an animated building tower showing.owned/.locked/ default rooms.#drop— Drop schedule with a four-segment countdown and upcoming drops list. Uses the yellow accent#F0C040exclusively.#explore— Six-card feature grid: Co-Op Exploration, Full Customisation, Scarce Supply, Social Hub, Prestige Address, Live Events.#cta— Email waitlist input with success state.#download— Mirror of the standalone download page.
Animation philosophy
Most elements have either anim-fade-left, anim-scale, or anim-fade-in
classes toggled .visible by an IntersectionObserver as they enter the viewport.
The result is a calm cascade: nothing jumps, everything settles into place.
11Download — download.html
A focused, dark, cinematic page for the download CTA.
Layered composition (back to front, by z-index)
| Layer | Element | Purpose |
|---|---|---|
| 0 | <video class="bg-video"> | Looping background footage of the world. |
| 1 | .bg-tint | Two stacked linear gradients darkening the edges. |
| 2 | .grain | SVG turbulence noise at 6% opacity, mix-blend-mode: overlay. |
| 3 | .hex-layer | Animated hexagonal grid (canvas). |
| 5 | .content | Eyebrow, title, logo, lede, buttons, meta. |
Hex canvas animation
The hex grid uses a flat-topped hexagon tiling. Each hex has its own pulse phase, offset by
its distance from the canvas center plus a tiny per-cell jitter. The phase cycles through:
FADE_IN (60) → HOLD (180) → FADE_OUT (60) → GAP_OFF (80). During fade phases
both opacity and scale ease via -(cos(πt) - 1) / 2. Active hexes draw a white-filled
fill at 10% alpha and a 1px stroke at 55%. Result: a slow radial wave like a heartbeat city map.
Buttons
Two buttons, rendered as wide rectangular cards with 28×28 OS icons (Windows tiles, Apple silhouette), an uppercase mono micro-label ("DOWNLOAD FOR"), a 14–18px humanist OS name ("Windows 10 / 11", "macOS · Universal"), and a right-arrow that nudges right on hover. The primary is solid red on red border; the alternate is frosted glass.
"Coming soon" modal
Triggered by either button. A .modal-backdrop with backdrop-filter: blur(10px),
a 560px panel that slides up and scales in, eyebrow with pulsing red dot, headline
"Almost there.", and email capture. Valid submit stores the email locally
(localStorage.setItem('arthis_notify_email', v)) and switches to green-bordered success.
Invalid emails shake the form with a 280ms keyframe.
12City Shell — city/index.html
A minimal shell whose only job is to host the Unity WebGL iframe and gracefully manage the cold-start delay.
Reveal flow
- Reads the slug from the URL path (
/city/<slug>), title-cases it (e.g.iron-lullaby→Iron Lullaby), and writes it into the<title>, visible header, and veil headline. - The Unity iframe posts
{ type: 'unity-ready' }whencreateUnityInstance(...).then(...)resolves. - On receipt,
reveal()runs: veil fades out (opacity 0 over 0.55s), header springs in (hdrSlidekeyframe), and once the veil's transition ends it's setdisplay: noneand.game-wrapshifts down 52px. - Two safety fallbacks fire
reveal()automatically: 12s for early errors, 30s as a hard ceiling. The user is never trapped behind the veil.
13Unity Viewer — city/viewer/index.html
Bare-minimum page. Dark background #231F20. A single full-viewport <canvas id="unity-canvas">.
createUnityInstance(canvas, { dataUrl: 'Build/ArthisLand(viewer)(unitybuild).data.gz', frameworkUrl: 'Build/ArthisLand(viewer)(unitybuild).framework.js.gz', codeUrl: 'Build/ArthisLand(viewer)(unitybuild).wasm.gz', streamingAssetsUrl: 'StreamingAssets', companyName: 'DefaultCompany', productName: 'ArthisLand(viewer)', productVersion: '0.1.0', matchWebGLToCanvasSize: true, }) .then(() => window.parent.postMessage({ type: 'unity-ready' }, '*')) .catch(message => { window.parent.postMessage({ type: 'unity-ready' }, '*'); // unblock the shell anyway alert(message); });
A single global UNITY_MOBILE_BREAKPOINT = 900 is set before the loader so the Unity build can adapt its input mode.
14Cross-Cutting Concerns
Responsiveness Strategy
- The Wall does not depend on browser scrolling; at
≤ 720pxit switches from cursor-position-pan to drag-pan, hides the kbd hint and tagline, restores OS cursor, docks detail panel as bottom sheet. - Marketing pages use fluid type (
clamp()),display: flexwithflex-wrap, and explicit@media (max-width: 768px)breakpoints. - All images are
object-fit: cover; background video usesobject-fit: cover+playsinlinefor iOS.
Accessibility
- Every brick is a real
<button>witharia-label="Open <title>". - Decorative blank bricks are
aria-hidden="true". - The detail panel has
role="dialog"andaria-label={brick.title}. - The Escape key closes any open detail panel.
- Modal email input has
autocomplete="email",required, andtype="email". - Reduced-motion users are not yet explicitly catered to — existing motion is short and never strobing.
Performance Notes
- Bricks are culled in
useMemoagainst the viewport with a 240px padding. With 900 bricks, only ~30–80 are mounted at any time. - The wall transform uses
translate3d(...)+scale(...)on a single.wallelement to keep everything on the GPU. will-change: transformon.wallopts into a dedicated composite layer.contain: layout painton.bricklimits style invalidation on hover.- Thumbnails are inline
data:image/svg+xml;utf8,...URIs — zero network requests. - The Unity build is iframed so its memory footprint can't affect the React main thread.
Data & Persistence
- The Wall reads its brick set from a synchronous
window.ARTHIS_DATA. No fetch on first paint. - Supabase is loaded before the data file so dynamic layers (wishlist, real plays count) can wire up without refactor.
- The waitlist forms on both
/about.htmland/download.htmlpersist the email tolocalStorageunderarthis_notify_email. No public backend submission — it is a stub.
Open Graph / Social
<meta property="og:title" content="ARTHIS.land - The Wall" /> <meta property="og:description" content="Explore the vertical city of Arthis." /> <meta property="og:image" content="https://arthis.land/assets/LOGO-3Edited.png" /> <meta property="og:url" content="https://arthis.land/" /> <meta property="og:type" content="website" />
15State Machines
The Wall — Focus / Pan
City — Iframe Reveal
Download Modal
16How to Read the Codebase
A short, ordered reading list for a new contributor:
- Open
index.html— see what scripts load and in what order. - Read
brick-data.jsfrombuildBricks()downward — understand the wall's geometry. - Read
app.jsxfrom the bottom (ReactDOM.createRoot) upward —Appis the heart. - Skim
styles.cssfor the visual contract (brick, focus, vignette, detail panel). - Read
tweaks-panel.jsxonly if you need to wire new tweak controls. - Open
about.htmlanddownload.html— self-contained, no JSX, plain<style>+<script>per file. - Open
city/index.htmlto understand the iframe reveal contract. - The Unity build is opaque from the website's point of view — only the
unity-readypostMessage matters.
17Glossary
| Term | Meaning |
|---|---|
| Brick | A single tile on the Wall. Real bricks are interactive; blank bricks are decorative edge filler. |
| Wall | The entire 900-brick mosaic. A scaled, translated <div> that holds every brick. |
| Stage | The fixed viewport container holding the Wall, vignette, deadzone indicator, and cursor. |
| Deadzone | Central circular region where cursor movement does NOT pan the Wall. Lets the user rest. |
| Running bond | Masonry pattern where every other row is offset by half a brick. |
| Detail panel | The 380px card that slides in when a brick is focused. |
| Tweaks panel | The floating, draggable design-time control panel. |
| Chrome | Non-interactive overlays (logo, kbd hint, coords HUD) at z-index 40. |
| Vignette | The radial darkening mask over the stage. |
| City | The Unity WebGL experience embedded under /city/. |
| Drop | A scheduled release of new rooms. |
| Room | Equivalent to a "brick" in marketing copy; a player-built space. |
Arthis