类型:Site模板 · 收录:2026-11-05 01:12:57 · 源码:会员可见
# Recreate this site as a single HTML file: Evolve
You are an expert creative front-end developer. Produce a **single self-contained `index.html`**
that reproduces the project below **exactly** — same layout, visuals, motion, and interaction.
Pure HTML/CSS/JS in one file: no build step, no framework, no bundler. Use ES modules with a CDN
importmap for Three.js 0.185.0. Hardcode every value given here as a fixed constant. Rebuild each
block described below as a section of the one file.
## What it is
A one-screen, jet-black hero for an AI infrastructure company. The subject is a **human head and
shoulders rendered as a point cloud** — tens of thousands of glowing particles lit by a blue key
light from front-left and a red rim light from back-right (magenta where they overlap), bloomed
into a soft haze that fills the frame. The cloud shimmers with a tiny per-point idle drift, turns
gently to follow the pointer (parallax), and particles scatter away from the cursor and spring
back behind it. Behind the subject: an eight-column hairline blueprint grid with small plus-shaped
crosshairs at rule intersections. Over it: an uppercase mono nav (PLATFORM · SOLUTIONS · RESEARCH ·
PRICING), a gradient-framed "GET STARTED" CTA with five cascading chevrons, a two-part display
headline — "Engineering / Intelligence" top-left, "That Evolves / With You." bottom-right — a mono
lead line bottom-left, and three grid-pinned stat labels whose figures settle out of scrambled
glyphs. Boot is a minimal cover: a mono percentage over a hairline track that fills with the
accent gradient, counting real milestones (fonts + first scene frame), then lifting. The whole
entrance is one authored timeline that begins only when the cover lifts.
## Page shell & libraries
- **Importmap:**
```html
<script type="importmap">
{ "imports": {
"three": "https://unpkg.com/three@0.185.0/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.185.0/examples/jsm/"
} }
</script>
```
From `three/addons/`: `postprocessing/EffectComposer.js`, `postprocessing/RenderPass.js`,
`postprocessing/UnrealBloomPass.js`, `postprocessing/OutputPass.js`,
`postprocessing/Pass.js` (for `Pass`/`FullScreenQuad`), `postprocessing/SavePass.js`.
- **Fonts** — two faces from Google Fonts:
```html
<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Inter+Tight:wght@400;500&family=Space+Mono&display=swap" />
```
→ `font-family: "Inter Tight", system-ui, sans-serif` for the headline and CTA label;
`font-family: "Space Mono", ui-monospace, monospace` for nav, stats, lead and the counter.
- **No scroll.** The hero is one `100dvh` section, `overflow: hidden`, background `#000000`.
Layer order is **DOM order** (no z-index except the noted ones): rule grid → particle canvas
(transparent, so the grid shows through *behind* the subject but the subject occludes it) →
nav/CTA/headline/stats/lead → preloader cover (`z 50`).
- **Adaptive rem grid** — root font-size scales with the viewport, exactly:
```css
html { font-size: 16px; }
@media (max-width: 1920px) { html { font-size: 0.833333vw; } }
@media (max-width: 1440px) { html { font-size: 1.111111vw; } }
@media (max-width: 1024px) { html { font-size: 1.5625vw; } }
@media (max-width: 640px) { html { font-size: 4.444444vw; } }
```
The desktop composition (≥1280px) is pixel-matched to a 1440×800 frame — 1rem = design-px/16.
- **Colour tokens:**
```css
:root {
--background: #000000;
--foreground: #ffffff;
--foreground-muted: rgb(255 255 255 / 0.4); /* stat labels */
--rule: rgb(255 255 255 / 0.15); /* inner grid rules */
--rule-strong: rgb(255 255 255 / 0.2); /* outer rules + stubs */
--marker: #666666; /* plus crosshairs */
--accent-start: #8dd8ff;
--accent-middle: #69beff;
--accent-end: #4c97ff;
--gradient-accent: linear-gradient(90deg,
var(--accent-start) 0%, var(--accent-middle) 45%, var(--accent-end) 100%);
--scene-key: #2f6bff; /* particle key light */
--scene-rim: #ff1f4a; /* particle rim light */
--scene-fill: #0a1430; /* particle ambient fill */
--hairline: 1px; /* never rem — stays crisp */
--duration-fast: 150ms; --duration-normal: 250ms;
}
```
- **Type scale** (desktop, rem): display `5.75rem` line-height 1 (Inter Tight 400); lead
`1.125rem` lh 1.2, letter-spacing −0.03em; nav `1rem` lh 1.3 uppercase; meta/stats `0.75rem`
lh 1.2 uppercase. Below 1280 use fluid sizes: display `clamp(42px, 6.3889vw, 82px)`, lead
`clamp(14px, 1.25vw, 16px)`, nav `clamp(13px, 1.1111vw, 14.22px)`, meta
`clamp(12px, 1.05vw, 14px)`.
## The device tiers
Resolved once at boot from `innerWidth`: `mobile` ≤ 767, `tablet` ≤ 1279 (also any wider viewport
with a coarse pointer), else `desktop`.
| | maxPixelRatio | point stride | frame budget | point size × | bloom | framing override |
|---|---|---|---|---|---|---|
| mobile | 0.85 | keep every 4th | 1000/30 ms | 0.68 | off | y −0.62, scale 0.78, camera 4.3 |
| tablet | 1.25 | every 2nd | 1000/45 ms | 1.1 | on | y −0.62, scale 1.24, camera 4.0 |
| desktop | 1.5 | every point | uncapped | 1 | on | none — authored config verbatim |
- The vertex buffer is **spatially sorted by X**, so down-sampling must **stride, never
truncate** — slicing the tail deletes one whole side of the head.
- Pointer effects (parallax, scatter) only on `(pointer: fine)`.
- On `prefers-reduced-motion` (or a mobile device with Data Saver / ≤2 GB memory): render **one
static frame** and never start the loop.
- The render loop also stops while the tab is hidden.
## The WebGL scene — the particle head
### Data
Fetch `vertices.json` (see Assets): `{ "objects": { "<name>": { "verts": [x,y,z, …] } } }` — one
flat vertex array, **Blender Z-up with the face toward −Y**. Convert each vertex to three.js
space as `[x, z, -y]`. The cloud is ~1.85 × 1.9 × 1.09 world units.
Per kept point (after striding), build three attributes:
- `position` — the converted vertex.
- `aNormal` — the source has no normals; approximate: direction from the (strided) centroid to
the point, with the **Y component multiplied by 0.35** before normalising. Reads convincingly
on a bust.
- `aRandom` — three uniform randoms in [−1, 1], fixed per point.
`geometry.computeBoundingSphere()` — the depth fade band is anchored to it. On the `Points`
object set `frustumCulled = false` (positions are displaced in the shader).
### Renderer, camera, composer
- `WebGLRenderer({ antialias: false, alpha: true, stencil: false, powerPreference: desktop ?
"high-performance" : "default" })`; clear colour `#000000` at **alpha 0** — the canvas is
transparent so the rule grid sits behind it and is occluded by the subject. Clamp
`setPixelRatio` to the tier (hard ceiling 1.5), on **both** renderer and composer.
- `PerspectiveCamera(fov 32, aspect, 0.1, 100)` at `z = 3.4` (camera distance; tier framing may
override to 4.0/4.3). Never rotated.
- The cloud sits in a `Group` at `(0.04, −0.37, 0)` (tier framing overrides y), scale `1.33`
(tier overrides), resting rotation `(0°, 24°, 0°)`.
- Composer chain: `RenderPass` → `UnrealBloomPass(strength 1.23, radius 0.4, threshold 0.2)` →
the **temporal filter pair** (below) → `OutputPass`.
- **Bloom runs at half the CSS size**: `bloomPass.setSize(clientWidth * 0.5, clientHeight * 0.5)`
— deliberately coarse; the blur smears the glow into the atmospheric haze that covers most of
the frame. Do not size it off the drawing buffer.
- Point size: `uScale = clientHeight * pixelRatio * 0.5`;
`uSize = 4.6 * tierPointSizeScale * pixelRatio * cameraDistance / uScale`. In the shader,
`gl_PointSize = uSize * (uScale / -viewPosition.z)`.
### The shaders (verbatim)
Vertex:
```glsl
attribute vec3 aNormal;
attribute vec3 aRandom;
uniform float uSize;
uniform float uScale;
uniform float uTime;
uniform vec3 uCursor;
uniform float uScatterRadius;
uniform float uScatterForce;
uniform float uTurbulence;
uniform float uDriftAmount;
uniform float uDriftSpeed;
uniform float uDepthNear;
uniform float uDepthFar;
uniform float uDepthStart;
uniform float uDepthStrength;
uniform vec3 uKeyColor;
uniform vec3 uRimColor;
uniform vec3 uFillColor;
varying vec3 vColor;
varying float vFade;
const vec3 KEY_DIR = vec3(-0.55, 0.25, 0.79);
const vec3 RIM_DIR = vec3(0.85, 0.08, -0.52);
const float KEY_WRAP = 0.5;
const float KEY_FALLOFF = 2.2;
const float KEY_INTENSITY = 1.5;
const float RIM_FALLOFF = 1.6;
const float RIM_INTENSITY = 1.3;
const float TAU = 6.2831853;
vec3 driftOffset(vec3 normal, vec3 seed, float t) {
vec3 guide = abs(normal.y) > 0.9 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
vec3 tangent = normalize(cross(normal, guide));
vec3 bitangent = cross(normal, tangent);
return tangent * sin(t * (1.00 + seed.x * 0.40) + seed.x * TAU)
+ bitangent * sin(t * (0.83 + seed.y * 0.40) + seed.y * TAU) * 0.9
+ normal * sin(t * (0.61 + seed.z * 0.40) + seed.z * TAU) * 0.3;
}
void main() {
vec3 normal = normalize(aNormal);
float key = pow(
max(0.0, dot(normal, normalize(KEY_DIR)) * KEY_WRAP + (1.0 - KEY_WRAP)),
KEY_FALLOFF
) * KEY_INTENSITY;
float rim = pow(
max(0.0, dot(normal, normalize(RIM_DIR))),
RIM_FALLOFF
) * RIM_INTENSITY;
vColor = min(vec3(1.0), uFillColor + uKeyColor * key + uRimColor * rim);
vec3 displaced = position;
if (uDriftAmount > 0.0) {
displaced += driftOffset(normal, aRandom, uTime * uDriftSpeed) * uDriftAmount;
}
if (uScatterForce > 0.0) {
vec3 away = displaced - uCursor;
float dist = length(away);
float influence = 1.0 - smoothstep(0.0, uScatterRadius, dist);
if (influence > 0.0) {
vec3 direction = normalize(away + aRandom * uTurbulence + vec3(1e-5));
displaced += direction * influence * uScatterForce;
}
}
vec4 viewPosition = modelViewMatrix * vec4(displaced, 1.0);
float through = clamp(
(-viewPosition.z - uDepthNear) / max(uDepthFar - uDepthNear, 1e-4),
0.0,
1.0
);
vFade = 1.0 - uDepthStrength * smoothstep(min(uDepthStart, 0.99), 1.0, through);
gl_PointSize = uSize * (uScale / -viewPosition.z);
gl_Position = projectionMatrix * viewPosition;
}
```
Fragment:
```glsl
varying vec3 vColor;
varying float vFade;
const float MIN_ALPHA = 0.004;
void main() {
vec2 offset = gl_PointCoord - 0.5;
float distanceSquared = dot(offset, offset);
if (distanceSquared > 0.25) discard;
float alpha = smoothstep(0.25, 0.02, distanceSquared) * vFade;
if (alpha < MIN_ALPHA) discard;
gl_FragColor = vec4(vColor, alpha);
#include <colorspace_fragment>
}
```
`ShaderMaterial({ transparent: true, depthWrite: true })`. Uniforms at their authored defaults:
`uScatterRadius 0.34`, `uTurbulence 1`, `uDriftSpeed 1`, `uDriftAmount 0.003` (0 when frozen),
`uDepthStart 0.35`, `uDepthStrength 0.85`, `uKeyColor #2f6bff`, `uRimColor #ff1f4a`,
`uFillColor #0a1430`. (`#include <colorspace_fragment>` is three's output-encoding chunk — keep
it or the colours read muddy.)
### Per-frame behaviour
- **Parallax**: track the pointer in the section's NDC, clamped to [−1, 1] on both axes (the
listener is on `window`). Ease `eased += (pointer − eased) * 0.04` per frame. Rotation:
`pitch = 0° + eased.y * 0.28 rad`, `yaw = 24° + eased.x * 0.45 rad`, roll 0.
- **Scatter**: when the pointer is inside the canvas and scatter is on, ramp `scatterAmount`
toward 1 (ease 0.09; toward 0 when it leaves). Project the eased pointer onto the model's
z-plane (ray from camera), lerp a smoothed cursor toward it (same 0.09), convert to the
group's **local** space every frame (parallax rotates it), and set `uScatterForce =
0.2 * scatterAmount`.
- **Depth fade band** (per frame, after the group is placed): centre = the bounding sphere's
centre through the group's world matrix; `centreDepth = camera.z − centre.z`;
`halfBand = sphereRadius * group.scale.x`; `uDepthNear = centreDepth − halfBand`,
`uDepthFar = centreDepth + halfBand`.
- **Idle skip**: compute the subject's screen motion this frame in CSS px —
`(|Δpitch| + |Δyaw|) * 1` (subject radius) plus the scatter-force/cursor deltas plus the
drift's own peak rate (`0.003 * 1 * scale * Δt` while drifting), all × pixels-per-world-unit
(`clientHeight / (2 * distance * tan(fov/2))`). Deltas are measured against the **last drawn**
frame. If a previous frame exists and motion < **0.05 px**, skip the draw entirely.
### The temporal filter (anti-flicker — part of the look's stability)
A dense point cloud flickers two ways; both are fixed at the end of the composer without touching
the artwork:
1. **Frame blend.** Keep a `SavePass` of the final frame. Before it, a full-screen shader pass
mixes the current frame with the saved one:
`gl_FragColor = mix(frame, lastFrame, uFrameMix)` where per drawn frame
`uFrameMix = 1 − (0.22 + 0.78 * smoothstep(motionPx, 0, 1.5))` — i.e. heavy history when the
subject is barely moving (weight of new frame bottoms out at 0.22), **zero history at ≥1.5 px
of motion** so movement never smears. After a resize, context loss or one-off render, reset
`uFrameMix` to 0 for that frame.
2. **Glow smoothing.** Bloom's finished glow lives in its own buffer before being added
(`bloomPass.renderTargetsHorizontal[0]`). Keep a ping-pong average of it:
`history = mix(history, glow, 0.15)` (weight 1 on the first frame after an invalidate), sized
to bloom's own buffer. In the frame-blend shader, subtract the *excess* of raw glow over the
averaged glow: `frame −= (texture(tGlow, uv) − texture(tGlowHistory, uv))` — the raw glow
cancels exactly and only the steadied one remains. Skip the correction entirely when bloom is
off (mobile).
Both passes use `NoBlending` and a pass-through vertex shader (`vUv = uv`).
### Boot
Fetch the JSON, build the geometry, `renderer.compile(scene, camera)`, draw **one frame through
the composer** (no history blend), then report ready to the preloader. If WebGL is unavailable or
the fetch fails, report nothing — the cover's failsafe opens the page without a subject.
## Layout & sections (desktop, 1440×800 reference; all rem)
The section is `position: relative; height: 100dvh; overflow: hidden`.
### The rule grid (behind the canvas, `aria-hidden`)
- Vertical hairlines (1px wide, full height) at 0% and 100% in `--rule-strong`; at 12.5%, 25%,
37.5%, 50%, 62.5%, 75% in `--rule`.
- The 87.5% rule is **split around the CTA**: a `--rule-strong` stub from the top, `1rem` tall;
then a `--rule` line from `top: 4.375rem` to the bottom.
- One horizontal `--rule` hairline at `top: 74.875%`.
- Eight plus-shaped crosshairs (11×11 SVG, `path "M6 5H11V6H6V11H5V6H0V5H5V0H6V5Z"`, fill
`--marker`, `0.6875rem` square, centred on the intersection) at: (75%, 1.9375%),
(37.5%, 11.6875%), (87.5%, 25.8125%), (25%, 50.9375%), (75%, 50.9375%), (12.5%, 74.875%),
(87.5%, 74.875%), (25%, 99.3125%). That order is the reveal order.
### Nav (top-left)
`position: absolute; top: 2.3125rem; left: 2.5rem; mix-blend-mode: difference`. A row of four
uppercase Space Mono links, gap `3rem`: PLATFORM · SOLUTIONS · RESEARCH · PRICING (`#platform`
etc.). Hover: opacity 0.7, 150ms.
### Scroll cue (top-centre)
A small 27×11 chevron SVG (see Assets — `scroll-cue.svg`) at `top: 2.3125rem`, horizontally
centred.
### CTA (top-right)
`top: 1rem; right: 2.5rem` — a `12.75rem × 3.375rem` box:
- **Hairline gradient frame**: a 1px border carrying `--gradient-accent` (pseudo-element with
`padding: 1px; background: var(--gradient-accent);
mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
mask-composite: exclude`).
- Label "GET STARTED", Inter Tight 500, `1rem`, uppercase, letter-spacing 0.015em,
`padding-left 1.5rem` — filled with the SAME ramp via `background-clip: text` with
`background-size: 12.75rem 100%; background-position: -1.5rem 0`, so frame, label and chevrons
all read one continuous gradient across the button.
- Five chevrons on the right (`left: 8.625rem`, a 42×15 SVG, viewBox `138 19.5 42 15`), each the
path `M138 34.1444L138.614 34.5L144 26.9725L138.614 19.5L138 19.8556L138 26.1513L138.818
26.9725L138 27.7937L138 34.1444Z` translated by `9` SVG units per index, filled with a
`userSpaceOnUse` linearGradient x1=0 → x2=204 of the same three accent stops (offsets 0 /
0.45 / 1).
- **Hover**: a fill layer (`--gradient-accent` at opacity 0.18) wipes in — `transform:
scaleX(0→1)`, origin left, 420ms on `cubic-bezier(0.16, 1, 0.3, 1)`; the chevrons run a
looping cascade — each translates +4 SVG units and back (reverse loop), 45ms stagger per
chevron, 420ms per leg. On leave, stop the loop and return every chevron to 0.
### Headline
One `<h1>` (Inter Tight 400, `5.75rem`, line-height 1, `pointer-events: none`), two absolute
pairs of hard-broken lines:
- "Engineering" / "Intelligence" — `top: 8.625rem; left: 2.5rem`, left-aligned.
- "That Evolves" / "With You." — `right: 2.5rem; bottom: 2.5rem`, right-aligned.
### Stats (grid-pinned, Space Mono `0.75rem`, uppercase, `--foreground-muted`, line-height 1.2)
Each sits `0.625rem` right of its rule: at `left: calc(87.5% + 0.625rem); top: 27.125%`, width
`7.125rem`: "99.99%" / "Platform uptime" (two lines); at `calc(75% + 0.625rem); top: 52.25%`,
width `7.125rem`: "45B+ Tokens processed daily"; at `calc(12.5% + 0.625rem); top: 70.875%`, width
`9.375rem`: "120+" / "Enterprise customers".
### Lead (bottom-left)
`bottom: 2.5rem; left: 2.5rem; width: 14.5625rem`, Space Mono `1.125rem`, line-height 1.2,
letter-spacing −0.03em: "From foundation models to production-ready infrastructure."
### Responsive
Below 1280: fluid type sizes; grid at 50% opacity. Below 768: the section becomes a flex column
(padding 1rem, top 5.5rem) — nav collapses into a 48px bordered toggle (three bars morphing to an
×) opening a dropdown menu, the CTA stays visible top-right at 48px tall, the headline collapses
into one left-aligned block, stats join the flow as single rows, the lead drops to the bottom;
the grid is hidden and a legibility scrim (vertical gradient, black 0.78 → transparent 34–58% →
black 0.55 at 78% → 0.78) sits over the subject.
## The loader / reveal
A fixed cover (`z 50`), background `#000000`, centred column `min(70vw, 26rem)` wide: a Space
Mono percentage (`0.75rem`, uppercase, `--foreground-muted`) above a 1px `--rule` track whose
fill (`--gradient-accent`) scales `scaleX(0→progress)`, origin left, 420ms per step on
`cubic-bezier(0.16, 1, 0.3, 1)`.
Progress counts **two real milestones**, not a timer: `document.fonts.ready` and the scene's
first rendered frame. Each advances the bar by half. Failsafe: at **6 s** force 100% regardless
(no WebGL must still open the page). At 100%, hold **260 ms**, then lift: opacity → 0 and
`translateY(−24px)` over 620ms on the same curve, then remove from the DOM.
**The entrance timeline is gated on the lift** — every animated element holds at its `from` state
until the cover has lifted, then runs its own delay.
## Entrance choreography
Shared curve `cubic-bezier(0.16, 1, 0.3, 1)` (call it EASE). "Fade" = opacity 0→1 +
translateY(±0.75rem→0), 700ms on EASE. Delays are ms after the cover lifts:
| element | animation | delay |
|---|---|---|
| nav | fade from above | 0 |
| scroll cue | fade from above | 0 |
| rule grid | plain opacity fade, 700ms | 200 |
| crosshairs | each: opacity 0→1 + `scale(0) rotate(−45deg)` → `scale(1) rotate(0)`, 700ms EASE | 200 + index·40 |
| particle head | wrapper fades in 700ms; inside it, `scale(1.06) → scale(1)` over **2500ms** EASE | 400 |
| "Engineering"/"Intelligence" | letter-by-letter (below) | 600 (+150 for line 2) |
| "That Evolves"/"With You." | letter-by-letter | 1400 (+150 for line 2) |
| stats | fade from below; figures scramble (below) | 2000 |
| lead copy | line-by-line: same letter shape but per wrapped line, 1000ms, 130ms stagger | 2000 |
| CTA | fade from above | 2400 |
- **Headline letters**: each glyph wrapped in a span; from `translateY(0.42em) + opacity 0 +
blur(10px)` to rest, **1150ms** on EASE, **22ms** stagger along the line, each line starting
**150ms** after the one above. No overflow clipping — blur and opacity carry the reveal.
- **Stat scramble**: the leading figure of each stat (`99.99%`, `45B+`, `120+`) renders as random
glyphs from `0123456789#%$&*+<>/` (same length, so the mono line never reflows), then settles
left-to-right over **700ms**, characters locking in as progress crosses their index ('.' and
',' never scramble). The real text must be in the DOM before JS touches it.
- Under `prefers-reduced-motion`, every entrance jumps straight to its end state and the scramble
never runs.
## Fixed parameters (bake these in)
```
SCENE camera fov 32 dist 3.4 (tablet 4.0, mobile 4.3) · model (0.04, −0.37, 0)
scale 1.33 (tablet 1.24, mobile 0.78) · modelY tablet/mobile −0.62 · rotY 24°
COLORS key #2f6bff · rim #ff1f4a · fill #0a1430 · bg #000000
LIGHTS KEY_DIR (−0.55, 0.25, 0.79) wrap 0.5 falloff 2.2 ×1.5
RIM_DIR (0.85, 0.08, −0.52) falloff 1.6 ×1.3
POINTS size 4.6 css-px (× tier 1 / 1.1 / 0.68) · stride 1/2/4 · soft disc, edge smoothstep
BLOOM strength 1.23 radius 0.4 threshold 0.2 · sized at 0.5 × CSS size · off on mobile
TEMPORAL idle skip < 0.05 px · min new-frame weight 0.22 · full motion 1.5 px
glow average weight 0.15 · subject radius 1
SCATTER force 0.2 · radius 0.34 · turbulence 1 · ease 0.09
DRIFT amount 0.003 · speed 1 · surface-tangent sines (0.61–1.4 rad/s per point)
DEPTH start 0.35 · strength 0.85 · band = bounding sphere through group matrix
PARALLAX yaw 0.45 rad · pitch 0.28 rad · ease 0.04 · pointer clamped to ±1
DPR ≤1.5 (desktop) / ≤1.25 (tablet) / ≤0.85 (mobile) · fps uncapped/45/30
TIMELINE nav 0 · grid 200 · visual 400 · titleLead 600 · titleTrail 1400 · stats 2000
cta 2400 · EASE cubic-bezier(0.16,1,0.3,1) · fade 700ms lift 0.75rem
LETTERS 1150ms · 22ms stagger · +150ms/line · from y 0.42em blur 10px
LEAD 1000ms/line · 130ms stagger SCRAMBLE 700ms glyphs 0123456789#%$&*+<>/
CTA 12.75rem × 3.375rem · ramp #8dd8ff → #69beff 45% → #4c97ff · fill 0.18 wipe 420ms
chevrons ×5 · offset 9 · travel 4 · stagger 45ms
GRID rules 12.5% steps · strong 20% white · inner 15% · horizontal 74.875%
split rule 87.5% (stub 1rem, resume 4.375rem) · markers #666 11×11 stagger 40ms
LOADER milestones fonts + first frame · failsafe 6s · settle 260ms · lift 620ms −24px
TYPE display 5.75rem lh 1 · lead 1.125rem −0.03em · nav 1rem · meta 0.75rem
LAYOUT margins 2.5rem · nav/cue top 2.3125rem · CTA top 1rem · headline top 8.625rem
```
## Copy (verbatim)
- Nav: `Platform` · `Solutions` · `Research` · `Pricing`; CTA: `Get Started`
- Headline: `Engineering` / `Intelligence` — then `That Evolves` / `With You.`
- Lead: `From foundation models to production-ready infrastructure.`
- Stats: `99.99%` Platform uptime · `45B+ Tokens processed daily` · `120+` Enterprise customers
## Assets
Load these exact URLs:
- Vertex buffer (~1.9 MB JSON): https://storage.getlayers.ai/assets/evolve-f940e12f08/vertices.json
- Scroll cue: https://storage.getlayers.ai/assets/evolve-f940e12f08/scroll-cue.svg
(Fonts come from Google Fonts — see "Page shell & libraries".)
If `vertices.json` fails to load, show a small visible notice over the black field (never a
silent empty hero), and still open the page via the loader's 6 s failsafe.[/hidecontent]