chore: format with prettier [skip ci]

This commit is contained in:
github-actions[bot] 2026-06-30 20:36:37 +00:00
parent 8579136b48
commit 48bdfc06b3
5 changed files with 120 additions and 103 deletions

View File

@ -210,43 +210,46 @@ export function LandingFeatures() {
[feedbackId],
);
useGSAP(() => {
// Desktop: pin the section so the viewport locks onto it, then advance
// through the four features (text + mockup crossfade) as you scroll, with a
// snap to each one. The pin owns a defined scroll region, so the layout and
// every trigger below stays stable. Mobile renders the features stacked.
const mm = gsap.matchMedia();
useGSAP(
() => {
// Desktop: pin the section so the viewport locks onto it, then advance
// through the four features (text + mockup crossfade) as you scroll, with a
// snap to each one. The pin owns a defined scroll region, so the layout and
// every trigger below stays stable. Mobile renders the features stacked.
const mm = gsap.matchMedia();
mm.add("(min-width: 1024px)", () => {
const st = ScrollTrigger.create({
trigger: pinRef.current,
pin: true,
start: "top top",
// Short, snappy travel between features (~0.6 viewport each) instead
// of a full screen of scrolling per switch.
end: () => "+=" + window.innerHeight * 1.8,
anticipatePin: 1,
invalidateOnRefresh: true,
snap: {
snapTo: [0, 1 / 3, 2 / 3, 1],
duration: { min: 0.25, max: 0.5 },
delay: 0.05,
ease: "power2.inOut",
},
onUpdate: (self) => {
const idx = Math.min(3, Math.round(self.progress * 3));
if (idx !== activeRef.current) {
activeRef.current = idx;
setActive(idx);
}
},
mm.add("(min-width: 1024px)", () => {
const st = ScrollTrigger.create({
trigger: pinRef.current,
pin: true,
start: "top top",
// Short, snappy travel between features (~0.6 viewport each) instead
// of a full screen of scrolling per switch.
end: () => "+=" + window.innerHeight * 1.8,
anticipatePin: 1,
invalidateOnRefresh: true,
snap: {
snapTo: [0, 1 / 3, 2 / 3, 1],
duration: { min: 0.25, max: 0.5 },
delay: 0.05,
ease: "power2.inOut",
},
onUpdate: (self) => {
const idx = Math.min(3, Math.round(self.progress * 3));
if (idx !== activeRef.current) {
activeRef.current = idx;
setActive(idx);
}
},
});
return () => st.kill();
});
return () => st.kill();
});
return () => mm.revert();
}, { scope: containerRef });
return () => mm.revert();
},
{ scope: containerRef },
);
// Fluid swap between features: outgoing fades out while the incoming text
// rises line-by-line and the mockup settles in with a soft scale. Runs on
@ -337,8 +340,8 @@ export function LandingFeatures() {
</div>
<div className="lg:col-span-5">
<p className="landing-body-compact">
Your agents stay native terminal tools. AO standardizes launch, restore, hooks, and PR ownership through one
adapter contract.
Your agents stay native terminal tools. AO standardizes launch, restore, hooks, and PR ownership through
one adapter contract.
</p>
</div>
</div>
@ -418,9 +421,10 @@ function FeatureNarrative({ worker, orchestrator }: { worker: AgentHarness; orch
meta="23 harnesses"
>
<p>
Run <FeatureStrong>{worker.name}</FeatureStrong>, <FeatureStrong>{orchestrator.name}</FeatureStrong>, Cursor,
or Aider unchanged. AO standardizes the workflow around them <FeatureStrong>restore, prompts, hooks, and
ownership</FeatureStrong> so you can pick one agent to write and another to supervise.
Run <FeatureStrong>{worker.name}</FeatureStrong>, <FeatureStrong>{orchestrator.name}</FeatureStrong>, Cursor, or
Aider unchanged. AO standardizes the workflow around them {" "}
<FeatureStrong>restore, prompts, hooks, and ownership</FeatureStrong> so you can pick one agent to write and
another to supervise.
</p>
</FeatureCopy>
);

View File

@ -555,30 +555,36 @@ function SessionDot({ zone }: { zone: string }) {
export function LandingHero() {
const containerRef = useRef<HTMLDivElement>(null);
useGSAP(() => {
const ctx = gsap.context(() => {
const tl = gsap.timeline({ defaults: { ease: "power4.out" } });
// Initial state
gsap.set(".gsap-reveal", { y: 40, opacity: 0 });
gsap.set(".gsap-scale", { scale: 0.95, opacity: 0 });
useGSAP(
() => {
const ctx = gsap.context(() => {
const tl = gsap.timeline({ defaults: { ease: "power4.out" } });
tl.to(".gsap-reveal", {
y: 0,
opacity: 1,
duration: 1.2,
stagger: 0.15,
})
.to(".gsap-scale", {
scale: 1,
opacity: 1,
duration: 1.2,
ease: "elastic.out(1, 0.75)"
}, "-=0.8");
}, containerRef);
// Initial state
gsap.set(".gsap-reveal", { y: 40, opacity: 0 });
gsap.set(".gsap-scale", { scale: 0.95, opacity: 0 });
return () => ctx.revert();
}, { scope: containerRef });
tl.to(".gsap-reveal", {
y: 0,
opacity: 1,
duration: 1.2,
stagger: 0.15,
}).to(
".gsap-scale",
{
scale: 1,
opacity: 1,
duration: 1.2,
ease: "elastic.out(1, 0.75)",
},
"-=0.8",
);
}, containerRef);
return () => ctx.revert();
},
{ scope: containerRef },
);
return (
<section
@ -629,8 +635,14 @@ export function LandingHero() {
<span>Star on GitHub</span>
<span className="relative inline-flex items-center">
<StarIcon className="gh-star h-4 w-4 text-[color:var(--fg-muted)]" />
<span className="gh-sparkle absolute -right-1 -top-1 h-1 w-1 rounded-full bg-[#ffd35c]" style={{ ["--sx" as string]: "7px", ["--sy" as string]: "-7px" }} />
<span className="gh-sparkle gh-sparkle-2 absolute -bottom-1 left-0 h-1 w-1 rounded-full bg-[color:var(--accent)]" style={{ ["--sx" as string]: "-6px", ["--sy" as string]: "6px" }} />
<span
className="gh-sparkle absolute -right-1 -top-1 h-1 w-1 rounded-full bg-[#ffd35c]"
style={{ ["--sx" as string]: "7px", ["--sy" as string]: "-7px" }}
/>
<span
className="gh-sparkle gh-sparkle-2 absolute -bottom-1 left-0 h-1 w-1 rounded-full bg-[color:var(--accent)]"
style={{ ["--sx" as string]: "-6px", ["--sy" as string]: "6px" }}
/>
</span>
<span className="gh-star-count rounded-full border border-white/10 bg-white/[0.04] px-1.5 py-0.5 text-[12px] leading-none text-[color:var(--fg-muted)]">
7.7k
@ -646,7 +658,7 @@ export function LandingHero() {
</div>
<div className="h-px flex-1 bg-gradient-to-r from-[color:var(--border-strong)] via-[color:var(--border-strong)] to-transparent" />
</div>
<div className="gsap-scale mt-12">
<ScaledMockup designWidth={1080}>
<HeroDashboardMockup />

View File

@ -132,16 +132,16 @@ export function LandingNav() {
}, []);
return (
<header data-testid="site-nav" ref={navRef} className="pointer-events-auto fixed inset-x-0 top-0 z-40 pt-4 px-4 transition-all duration-500 ease-out flex justify-center [&.nav-scrolled]:pt-2">
<div
<header
data-testid="site-nav"
ref={navRef}
className="pointer-events-auto fixed inset-x-0 top-0 z-40 pt-4 px-4 transition-all duration-500 ease-out flex justify-center [&.nav-scrolled]:pt-2"
>
<div
ref={innerRef}
className="w-full max-w-6xl mx-auto flex h-14 items-center justify-between gap-6 rounded-full border border-[color:var(--border)] bg-[color:var(--bg)]/70 px-6 backdrop-blur-xl shadow-lg transition-all duration-500 ease-out [.nav-scrolled_&]:h-12 [.nav-scrolled_&]:max-w-4xl [.nav-scrolled_&]:bg-[color:var(--bg)]/90"
>
<a
href="/"
data-testid="nav-logo"
className="group inline-flex h-10 shrink-0 items-center gap-3"
>
<a href="/" data-testid="nav-logo" className="group inline-flex h-10 shrink-0 items-center gap-3">
<img
src="/ao-logo.svg"
alt="Agent Orchestrator"
@ -152,10 +152,7 @@ export function LandingNav() {
</span>
</a>
<nav
className="hidden items-center gap-8 md:flex"
aria-label="Primary"
>
<nav className="hidden items-center gap-8 md:flex" aria-label="Primary">
{navLinks.map((item) => (
<a
key={item.label}

View File

@ -125,33 +125,36 @@ function VerifiedIcon({ className = "" }: { className?: string }) {
export function LandingSocialProof() {
const containerRef = useRef<HTMLElement>(null);
useGSAP(() => {
const cards = gsap.utils.toArray<HTMLElement>(".gsap-tweet-card");
useGSAP(
() => {
const cards = gsap.utils.toArray<HTMLElement>(".gsap-tweet-card");
gsap.set(cards, { opacity: 0, y: 30 });
gsap.set(cards, { opacity: 0, y: 30 });
// Reveal each card as it enters the viewport. On mobile the masonry is a
// single tall column, so a single section-top trigger left the lower cards
// invisible until far past the heading; batching reveals them in step with
// the scroll on every layout.
const batch = ScrollTrigger.batch(cards, {
start: "top 90%",
once: true,
onEnter: (els: Element[]) => {
gsap.to(els, {
opacity: 1,
y: 0,
duration: 0.7,
stagger: 0.08,
ease: "power3.out",
});
},
});
// Reveal each card as it enters the viewport. On mobile the masonry is a
// single tall column, so a single section-top trigger left the lower cards
// invisible until far past the heading; batching reveals them in step with
// the scroll on every layout.
const batch = ScrollTrigger.batch(cards, {
start: "top 90%",
once: true,
onEnter: (els: Element[]) => {
gsap.to(els, {
opacity: 1,
y: 0,
duration: 0.7,
stagger: 0.08,
ease: "power3.out",
});
},
});
ScrollTrigger.refresh();
ScrollTrigger.refresh();
return () => batch.forEach((t) => t.kill());
}, { scope: containerRef });
return () => batch.forEach((t) => t.kill());
},
{ scope: containerRef },
);
return (
<section
@ -249,9 +252,7 @@ function TweetCard({ post, index }: { post: Post; index: number }) {
<span className="truncate text-[14px] font-semibold leading-tight text-[color:var(--fg)]">
{post.author}
</span>
{post.verified ? (
<VerifiedIcon className="h-3.5 w-3.5 shrink-0 text-[color:var(--accent)]" />
) : null}
{post.verified ? <VerifiedIcon className="h-3.5 w-3.5 shrink-0 text-[color:var(--accent)]" /> : null}
</div>
<span className="truncate text-[12px] leading-tight text-[color:var(--fg-dim)]">@{post.handle}</span>
</div>

View File

@ -130,7 +130,11 @@ body::-webkit-scrollbar,
min-height: 100vh;
background: var(--bg);
color: var(--fg);
font-family: var(--font-inter), -apple-system, system-ui, sans-serif;
font-family:
var(--font-inter),
-apple-system,
system-ui,
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
@ -979,4 +983,3 @@ body::-webkit-scrollbar,
transform-box: fill-box;
animation: landing-graph-pulse 1.5s ease-out infinite;
}