How This Site
Was Built.
A working record of the concept, the art direction behind the imagery, the build techniques, and the deployment path behind the Monolith Studio showcase — written so the decisions can be reproduced or adapted.
01 — Concept
Monolith Studio is a fictional brutalist architecture practice. The brief was to push swiss/international-typographic grid discipline to a brutalist extreme: oversized grotesque type, hard edges, a raw monochrome palette, exactly one bold accent color, and a visible structural grid — the layout itself reads like a working drawing, not a decorated page.
The core visual conceit is that the page behaves like the buildings it's describing: elements are gridded, load-bearing, and unornamented. The only "decoration" allowed is the accent color, used the way a site foreman uses hazard paint — sparingly, to mark the one thing that matters.
02 — Palette & Type
Type is a single grotesque family, Archivo (Google Fonts, weights 100–900), used at extreme contrast — a ~10–13vw display weight for headlines against 11px mono labels for metadata. The mono counterpart is Space Mono, used exclusively for coordinates, index numbers, captions and the roster — anything that reads as "annotation" rather than "statement."
Both are loaded as standard <link> tags from Google Fonts — no build step, no self-hosting, matching the plain HTML/CSS/JS constraint for this build.
03 — Imagery: art direction
All eight photographs were generated with Higgsfield's Nano Banana Pro model at 2K resolution, then converted to compressed JPEG at 1920px max width with macOS sips to keep the folder lightweight (~7.5 MB total across 8 images). Each image — the hero mass shot, the six project photographs, and the board-formed concrete detail — was generated from a carefully art-directed brief specifying the lens, light direction, grain, composition, and mood, biased toward genuine architectural photography conventions rather than a generic "brutalist building" description, which tends to produce illustration-like results. Each was iterated until it held the monochrome print quality of the set. The full prompt library is proprietary and available to clients on request.
grayscale(1) contrast(1.1) CSS filter is still applied on top in style.css as a safety net so any color drift between generations reads as one consistent print.04 — The scroll-driven 3D building massing
This is the site's signature technique, in js/scene.js. It is not a looping animation — it is a deterministic function of scroll position, built on plain Three.js (r149, UMD build, no bundler) and GSAP ScrollTrigger for the scroll math.
How it works
- Six extruded volumes (
THREE.BoxGeometry) stand in for a stepped brutalist massing: a podium, a core tower, a cantilevered block, a support fin, a podium wing, and one slim accent-colored blade — mirroring the "one bold accent, used sparingly" rule in 3D. - Every volume gets a matching
THREE.LineSegmentsbuilt fromTHREE.EdgesGeometry, drawn in off-white at low opacity. This is what gives the forms their technical-drawing edge — a low-poly box alone reads as a toy; a box with crisp wireframe edges reads as a structural diagram. - Each volume has four keyframe positions — MASS, VOID, CANTILEVER, ASSEMBLY — hand-placed to tell a specific structural story: everything starts collapsed into one undivided block, then separates to open gaps ("void"), then the cantilevered block is pushed dramatically outward past its support, then the whole composition locks into its final stepped form.
- A single
ScrollTriggeris created on the pinned#assemblysection (scrub: 0.5, nomarkers). ItsonUpdatecallback receivesself.progress(0→1 across the pin) every scroll tick and callsapplyProgress(). applyProgress()divides progress into three equal segments, applies asmoothstepease within the active segment, and linearly interpolates each volume's position between its keyframes for that segment — this is what makes the assembly feel directly grabbed by the scrollbar rather than playing on a timer.- The whole group also rotates (
group.rotation.y = progress * Math.PI * 0.85) and the camera slowly dollies in (camera.position.zlerped from 13.5 → 10.6) over the same progress value, so orbit and dolly are scroll-scrubbed too, not just the assembly. - The accent blade fades in via material opacity only after progress passes 0.36 — a deliberate reveal so the one accent color arrives as a payoff partway through the sequence rather than being visible from frame one.
- The same
progressvalue drives the on-screen mono labels (stage number, stack list, caption heading/copy) via a small stage-index lookup — DOM and 3D read from the identical scroll number, so they can never drift out of sync.
Hero canvas (secondary scene)
The hero background runs a second, lighter Three.js scene: the same six-volume language in an ambient exploded cluster that idles with a slow autorotation and gets a subtle additional rotation/parallax tied to hero scroll progress. It exists to make the page feel alive on load, before the user has scrolled far enough to reach the pinned assembly sequence.
Performance / mobile degrade
- Pixel ratio is capped (
Math.min(devicePixelRatio, 1.4)under 760px width,2above) rather than left uncapped, which is the single biggest win for phone GPUs. - Antialiasing is disabled below the same breakpoint.
- Geometry count never scales with viewport — it's always six boxes plus six edge overlays in each scene, so there's no heavy branch to maintain for mobile; the cap on pixel ratio and AA is what keeps frame time down.
prefers-reduced-motion: reduceis respected — both scenes render once in their resolved end-state instead of animating.
05 — Other techniques worth naming
Visible swiss grid as a design element
A fixed, pointer-events-disabled 12-column overlay (.grid-overlay) sits above the whole page at mix-blend-mode: difference, so the column rules stay visible against both the black hero and the white section backgrounds without needing two separate color variants. Its opacity is nudged up slightly by GSAP once the "Works" section scrolls into view, reinforcing the transition from hero to content.
Line-item project list instead of a photo bento grid
The projects section (#works) intentionally is not a conventional image grid. Each project is a single full-width typographic row (index, name, meta, arrow) — closer to a drawing schedule than a portfolio tile. Hovering a row on desktop drives a small floating image preview that follows the cursor (GSAP quickTo-style tweening on mousemove); clicking a row expands a full-bleed image panel inline via a height transition. This keeps the page's information density brutalist and text-first while still surfacing the generated photography.
Coordinate-readout cursor
On fine-pointer devices, the default cursor is replaced with a small ring that reports live X/Y pixel coordinates, styled like a drafting cursor. It's throttled to one DOM write per animation frame via requestAnimationFrame, and is skipped entirely on touch devices via a (hover: hover) and (pointer: fine) media query check in JS, so it never intercepts taps on mobile.
Marquee strip
A single CSS @keyframes marquee (transform: translateX(-50%) on a doubled span) carries the material vocabulary — STRUCTURE, MATERIAL, VOID, MASS, LIGHT, LOAD — as a horizontal band between Philosophy and Process. It's pure CSS, no JS, and duplicated content rather than JS-cloned so it works even if scripts fail to load.
06 — Responsiveness
| Breakpoint | What changes |
|---|---|
| <900px | Grid overlay drops to 6 columns; top nav collapses to a MENU toggle; assembly's side stack list hides (caption block remains); all section grids reflow to a 6-column layout; hover-only preview thumbnail is disabled. |
| <760px | Three.js pixel ratio cap drops to 1.4 and antialiasing turns off in both scenes. |
| <480px | Contact info columns stack to full width. |
Verified at 375px and standard desktop widths — text never overflows its column, the pinned assembly section still resolves to a readable single caption block, and contrast (near-black text on off-white, off-white on near-black) stays well above WCAG AA at every size.
07 — Deployment
This is a static site with zero build step — plain HTML/CSS/JS plus CDN-hosted GSAP and Three.js and Google Fonts. Deployment is a drag-and-drop or CLI push of the monolith-studio/ folder to Netlify:
- Create a new Netlify site and point it at this folder (or connect the repo and set the publish directory to
monolith-studio/). - No build command is required — set the publish directory only; there is nothing to compile.
- Netlify serves
index.htmlat the root andguide/index.htmlat/guide/automatically since both are already laid out as static files with relative asset paths. - Because every asset reference in the HTML/CSS is relative (e.g.
assets/hero-monolith.jpg), the folder is portable to any static host without path rewrites.
We do not decorate structure. We reveal it.