How this was made
This concept site — art direction, copy, code, artwork and deployment — was produced end-to-end by Claude, an AI agent, in a single autonomous session. No templates, no frameworks, no build step. Here is the recipe.
1 · Research before design
The agent pulled the group's real positioning from public sources — practice areas, ranked-tier status, notable matters, the full team list — and read the firm's internal house-style toolkit for context. Design decisions came after the facts.
2 · A brand system, not a page
Palette: ink-petrol darks pulled toward the firm's greens (#8dc63f lime as
the single accent, always on near-black). Type: Instrument Serif for display —
a sharp, confident face that reads “City institution, current decade” — with Inter for
body and Spline Sans Mono for labels, indices and coordinates. All fonts
self-hosted as woff2.
3 · The visual tricks
- Hero — a GPU particle field, described in full below.
- Kinetic headline — split into characters at runtime (tag-safe DOM walk), each rising through an overflow mask with a 28 ms stagger and a slight rotation settle; the lime italic carries a continuous gradient sheen.
- Sector marquee — an infinite CSS-only ticker along the hero's base.
- Word-lighting — the positioning statement illuminates word-by-word as you scroll, DOM-walked so inline markup survives.
- Accordion — the eight practice areas use CSS
grid-template-rows: 0fr→1frtransitions: buttery height animation, zero JS measurement. - Track-record cards — 3-D tilt following the pointer with a radial glow that
tracks the cursor (
--gx/--gycustom properties). - Magnetic buttons and a scroll progress bar in brand lime.
4 · The hero: 50,176 particles, simulated on the GPU
The hero is not a video and not a shader painting a surface — it is a physics simulation of fifty thousand independent particles, run entirely on the graphics card, every frame.
- State lives in textures. Each particle's position and velocity occupy one texel of a pair of 224×224 floating-point textures. A fragment shader reads the current state and writes the next one into a second pair through multiple render targets; the two pairs swap each step. The CPU never touches a particle.
- Forces. A spring pulls every particle toward its target position, with per-particle stiffness so the form assembles in waves rather than all at once. Curl noise — the curl of a 3-D simplex-noise potential, so the flow is divergence-free — keeps the whole field breathing. The pointer parts the particles with a force that scales with how fast you move; a click sends a shock front through them.
- Fixed timestep. The integrator runs at a locked 1/60 s and catches up after a hitch, so the physics is identical on a 60 Hz laptop and a 144 Hz monitor.
- The forms are the practice. Four target sculptures are generated procedurally in JavaScript: a receding portico of fluted columns (the firms), a single monolith with an orbiting ring (the firm), a ruled page with a signature and a wax seal (the agreement), and a graph of nodes and bowed edges (the network). Switching form just swaps the target texture — the physics does the morph, loosening the springs and spiking the turbulence so the sculpture dissolves and re-crystallises. The headline underlines itself in step: the firm, then the firms.
- Rendering. Points are drawn with no vertex buffer at all — the vertex
shader derives each particle's texel from
gl_VertexID— additively blended over a background that is re-drawn at 13% opacity each frame, which is what leaves the comet trails. A threshold-and-blur bloom at quarter resolution, a filmic tone curve, chromatic aberration and grain finish the image. - Graceful degradation. No WebGL2 or no float render targets, and the page
falls back to the previous generation's flow-noise shader;
prefers-reduced-motionholds the sculpture still. Mobile drops to 16,384 particles.
5 · The artwork is generated
The silk hero and marble texture were generated with the Flux.1-dev diffusion model on a private ComfyUI render node (“Asuka Studio”), prompted in the brand palette and converted to WebP with ffmpeg. Total render time: about a minute.
6 · Ship & iterate
Deployed as static files straight to Netlify's deploy API. Then three deliberate review passes: screenshot at desktop and mobile widths, hunt for rhythm problems, dead zones, contrast failures and widowed lines, fix, repeat. The review loop is the real technique — everything else is just taste.