feat(marketing): redesign landing as "trusted infrastructure"
Re-skins the playful/consumer feel into disciplined agent-infrastructure,
keeping the animated hero canvas (re-themed) and adding the hierarchy story.
- Palette: re-point coral→ember (#E0584A); add ink/surface/mist/slate-light/
azure/teal tokens. One accent per viewport; retire the black/coral split-
headline pattern across all 8 headings (single ink color).
- Typography: hero/section weights 800→~650-675, tighter tracking, smaller
hero size; uppercase eyebrow label.
- Hero: dark ink base with glowing azure/indigo + faint ember canvas blooms;
light copy; new positioning ("Build safe, scalable agentic systems" + the
single-agent-to-company subhead); ember primary CTA + ghost "Read the docs".
- Imagery overhaul (code-built, no mascots): AgentToken chips (CrewStrip,
OneClick card, footer), AlwaysOn rebuilt as a terminal/log with an approval
line, SkillsShowcase as duotone lucide cards on Mist, Security as a shield/
lock motif.
- New HierarchyDiagram section ("One agent, or a whole org chart"): SVG org
chart with an azure active path and teal human-approval checkpoints on
sandbox-leaving actions.
- Tests: dark-hero/terminal/eyebrow contrast fixed to AA; refreshed the
marketing @visual baseline (hero masked).
Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
4b55c4d81e
commit
44512a744f
@@ -6,8 +6,8 @@ import { useEffect, useRef } from "react";
|
||||
* (js/shift.js): a few dozen large circles drift at random, their hue driven by
|
||||
* 3D simplex noise at their position + time; everything is drawn to an offscreen
|
||||
* buffer, then blurred and composited onto the visible canvas over a flat base.
|
||||
* Re-tuned to a light, brand palette (pale periwinkle base; soft blue→violet→coral
|
||||
* blooms) so the dark hero copy stays readable. Scoped to its container, not the
|
||||
* Re-themed to a dark, infrastructure palette (deep-ink base; glowing azure/indigo
|
||||
* blooms with a faint ember). Light hero copy sits on top. Scoped to its container, not the
|
||||
* window. Respects prefers-reduced-motion and pauses when scrolled out of view. */
|
||||
|
||||
// --- tunables (all easy to tweak) ---------------------------------------
|
||||
@@ -16,16 +16,19 @@ const BASE_SPEED = 0.06;
|
||||
const RANGE_SPEED = 0.7;
|
||||
const BASE_TTL = 180;
|
||||
const RANGE_TTL = 260;
|
||||
const BASE_RADIUS = 120;
|
||||
const RANGE_RADIUS = 240;
|
||||
const BASE_RADIUS = 140;
|
||||
const RANGE_RADIUS = 260;
|
||||
const NOISE_OFF = 0.0015; // x/y/z noise sampling step
|
||||
const BLUR_PX = 50;
|
||||
const BASE_COLOR = "#edf3fc"; // pale periwinkle base (matches the hero fill)
|
||||
const HUE_MIN = 205; // blue
|
||||
const HUE_MAX = 360; // → indigo / violet / magenta / coral
|
||||
const SAT = 70;
|
||||
const LIGHT = 74;
|
||||
const ALPHA = 0.5; // peak blob opacity (scaled by fade-in/out)
|
||||
const BLUR_PX = 55;
|
||||
const BASE_COLOR = "#0b1220"; // deep ink — blooms read as glowing light sources
|
||||
const ALPHA = 1; // global multiplier on each blob's peak alpha
|
||||
// Cool glow palette on dark [r, g, b, peakAlpha]. Azure + indigo dominate; a
|
||||
// faint ember adds warmth (re-themed from the original hue-band approach).
|
||||
const PALETTE: [number, number, number, number][] = [
|
||||
[59, 130, 246, 0.22], // azure #3B82F6
|
||||
[79, 70, 229, 0.18], // indigo #4F46E5
|
||||
[224, 88, 74, 0.12], // ember #E0584A (faint, rare)
|
||||
];
|
||||
|
||||
const TAU = Math.PI * 2;
|
||||
const rand = (n: number) => n * Math.random();
|
||||
@@ -152,17 +155,18 @@ export function HeroAmbient() {
|
||||
|
||||
const simplex = new SimplexNoise();
|
||||
const circles = new Float32Array(CIRCLE_COUNT * PROPS);
|
||||
let baseHue = HUE_MIN;
|
||||
let tick = 0;
|
||||
let raf = 0;
|
||||
let running = true;
|
||||
|
||||
function initCircle(i: number) {
|
||||
const x = rand(a.width);
|
||||
const y = rand(a.height);
|
||||
const n = simplex.noise3D(x * NOISE_OFF, y * NOISE_OFF, baseHue * NOISE_OFF);
|
||||
const n = simplex.noise3D(x * NOISE_OFF, y * NOISE_OFF, tick * NOISE_OFF);
|
||||
const ang = rand(TAU);
|
||||
const speed = BASE_SPEED + rand(RANGE_SPEED);
|
||||
const hue = HUE_MIN + ((n + 1) / 2) * (HUE_MAX - HUE_MIN);
|
||||
// Noise picks the glow color: azure dominant, indigo next, ember rare.
|
||||
const colorIndex = n > 0.05 ? 0 : n > -0.4 ? 1 : 2;
|
||||
circles.set(
|
||||
[
|
||||
x,
|
||||
@@ -172,7 +176,7 @@ export function HeroAmbient() {
|
||||
0,
|
||||
BASE_TTL + rand(RANGE_TTL),
|
||||
BASE_RADIUS + rand(RANGE_RADIUS),
|
||||
hue,
|
||||
colorIndex,
|
||||
],
|
||||
i,
|
||||
);
|
||||
@@ -184,10 +188,11 @@ export function HeroAmbient() {
|
||||
life: number,
|
||||
ttl: number,
|
||||
radius: number,
|
||||
hue: number,
|
||||
colorIndex: number,
|
||||
) {
|
||||
const [r, g, b, peak] = PALETTE[colorIndex] ?? PALETTE[0];
|
||||
actx.save();
|
||||
actx.fillStyle = `hsla(${hue},${SAT}%,${LIGHT}%,${fadeInOut(life, ttl) * ALPHA})`;
|
||||
actx.fillStyle = `rgba(${r},${g},${b},${fadeInOut(life, ttl) * peak * ALPHA})`;
|
||||
actx.beginPath();
|
||||
actx.arc(x, y, radius, 0, TAU);
|
||||
actx.fill();
|
||||
@@ -216,8 +221,7 @@ export function HeroAmbient() {
|
||||
actx.clearRect(0, 0, a.width, a.height);
|
||||
bctx.fillStyle = BASE_COLOR;
|
||||
bctx.fillRect(0, 0, b.width, b.height);
|
||||
baseHue += 0.05; // slow drift keeps the band gently shifting
|
||||
if (baseHue > HUE_MAX) baseHue = HUE_MIN;
|
||||
tick++; // advances the noise field used when respawning circles
|
||||
for (let i = 0; i < circles.length; i += PROPS) updateCircle(i);
|
||||
bctx.save();
|
||||
bctx.filter = `blur(${BLUR_PX}px)`;
|
||||
|
||||
Reference in New Issue
Block a user