From 48ee5ae085d02fb7316c557dcebb6ce7da950ea5 Mon Sep 17 00:00:00 2001 From: murilopmachado Date: Tue, 4 Aug 2026 21:37:53 +0200 Subject: [PATCH] feat: differentiated hero + GSAP motion for aigate marketing site Replace the generic text-left/terminal-right hero with a stacked layout: hero copy on top, then a full-width CSS/SVG sandbox-boundary diagram below, drawn to aigate's actual mechanism -- an AI agent process inside a kernel-enforced perimeter with FILE/EXEC/NETWORK gates. Syscalls (reused from the site's existing demo data: deny_read, deny_exec, allow_net) travel from the process toward a gate; allowed ones pass through to an external host pill, blocked ones bounce back inside the boundary. Motion via GSAP 3.12.5 + ScrollTrigger (CDN): - Hero entrance timeline: kicker -> h1 -> lede -> ctas -> trust line -> diagram, staggered on load. - Boundary "sealing" draw-in (stroke-dashoffset on the rect, measured via getTotalLength) followed by corner brackets, process box, gates, and the destination pill popping in, then a looping pair of syscall dots crossing/bouncing on a timer. - Scroll-triggered fade+rise reveals, staggered per section, once per section (isolation, platforms, commands, usecases, install). Reduced-motion guard: a single top-level `prefers-reduced-motion` check short-circuits the whole script before anything is hidden, so the page renders in its full, final, visible state by default (progressive enhancement) rather than depending on JS to reveal content. Verified with a real prefers-reduced-motion emulation, not just code review. Dropped the old feed-window/terminal-box markup and its now-dead CSS; kept .feed-caption/.pulse-dot/.feed-tone* since the isolation feature cards still use them. No changes to brand tokens, topbar, footer, or SEO head tags. --- web/index.html | 318 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 250 insertions(+), 68 deletions(-) diff --git a/web/index.html b/web/index.html index 651ea4d..a1eda5c 100644 --- a/web/index.html +++ b/web/index.html @@ -61,7 +61,7 @@ .topbar-nav a.navlink { color: var(--af-text-muted); text-decoration: none; } .topbar-nav a.navlink:hover { color: var(--af-text); } - /* ---- Hero: asymmetric two-column ---- */ + /* ---- Hero: stacked -- text band, then a full-width architecture diagram ---- */ .hero { background-image: radial-gradient(circle, var(--af-line) 1px, transparent 1px); background-size: 32px 32px; @@ -69,13 +69,10 @@ border-bottom: 1px solid var(--af-line); } .hero .wrap { - display: grid; - grid-template-columns: minmax(0, 1.05fr) minmax(320px, 0.95fr); - gap: 3rem; - align-items: center; - padding-top: 4.5rem; - padding-bottom: 4.5rem; + padding-top: 4rem; + padding-bottom: 2.5rem; } + .hero-copy { max-width: 62ch; } .kicker { font-family: var(--af-font-mono); font-size: 0.8rem; @@ -115,7 +112,8 @@ .trust-line a { color: var(--af-accent); text-decoration: none; } .trust-line a:hover { text-decoration: underline; } - /* ---- Live audit-log demo ---- */ + /* ---- Live caption + severity dots (reused by the boundary diagram legend + and by the isolation feature cards below) ---- */ .feed-caption { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.6rem; font-size: 0.8rem; color: var(--af-text-muted); } .pulse-dot { position: relative; width: 8px; height: 8px; border-radius: 50%; background: var(--af-accent); flex: none; } .pulse-dot::after { @@ -123,29 +121,44 @@ animation: pulse 2s ease-out infinite; } @keyframes pulse { 0% { opacity: 0.6; transform: scale(1); } 100% { opacity: 0; transform: scale(2.8); } } - #feed-window { box-shadow: 0 30px 60px -20px rgb(0 0 0 / 0.6); max-width: 100%; } - #feed-banner { padding: 0.85rem 1rem 0.4rem; font-family: var(--af-font-mono); font-size: 0.78rem; color: var(--af-text-muted); border-bottom: 1px solid var(--af-line); } - #feed-banner div { padding: 0.1rem 0; white-space: pre-wrap; overflow-wrap: anywhere; } - #feed-body { min-height: 11rem; max-height: 11rem; padding: 0.6rem 1rem 0.85rem; overflow: hidden; font-family: var(--af-font-mono); font-size: 0.82rem; } - .feed-line { - display: grid; grid-template-columns: auto auto minmax(0, 1fr) auto; gap: 0.6rem; align-items: baseline; - padding: 0.3rem 0; color: var(--af-text-muted); - animation: feed-in 0.4s cubic-bezier(0.16, 1, 0.3, 1); - } - .feed-line .title { overflow-wrap: break-word; } - @keyframes feed-in { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: translateY(0); } } - .feed-line .sev { text-transform: uppercase; font-size: 0.72rem; } - .feed-line .title { color: var(--af-text); } - .feed-line .who { color: var(--af-text-muted); opacity: 0.75; text-align: right; } .feed-tone { width: 6px; height: 6px; border-radius: 50%; align-self: center; } .feed-tone-info { background: #22d3ee; } .feed-tone-warn { background: #ffb000; } .feed-tone-critical { background: var(--af-accent); box-shadow: 0 0 8px color-mix(in srgb, var(--af-accent) 60%, transparent); } @media (prefers-reduced-motion: reduce) { - .feed-line { animation: none; } .pulse-dot::after { animation: none; opacity: 0; } } + /* ---- Boundary diagram: aigate's actual mechanism, drawn ---- */ + .boundary-stage { + border-top: 1px solid var(--af-line); + background: color-mix(in srgb, var(--af-surface) 45%, transparent); + padding: 2.25rem 0 3rem; + } + .boundary-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; } + .boundary-diagram { min-width: 760px; } + #boundary-svg { display: block; width: 100%; height: auto; } + #boundary-rect { fill: none; stroke: var(--af-accent); stroke-width: 2.5; opacity: 0.85; filter: drop-shadow(0 0 10px color-mix(in srgb, var(--af-accent) 45%, transparent)); } + .corner-bracket { fill: none; stroke: var(--af-accent); stroke-width: 3; stroke-linecap: square; } + .process-box { fill: var(--af-surface); stroke: var(--af-line); stroke-width: 1.5; } + .process-label { font-family: var(--af-font-mono); font-size: 15px; letter-spacing: 0.05em; fill: var(--af-text); font-weight: 600; text-transform: uppercase; } + .process-sublabel { font-family: var(--af-font-mono); font-size: 11px; fill: var(--af-text-muted); } + .gate-notch { fill: var(--af-bg); stroke: var(--af-line); stroke-width: 2; transition: fill 0.2s ease, stroke 0.2s ease, filter 0.2s ease; } + .gate-notch.tone-critical { stroke: var(--af-accent); fill: color-mix(in srgb, var(--af-accent) 30%, var(--af-bg)); filter: drop-shadow(0 0 7px color-mix(in srgb, var(--af-accent) 70%, transparent)); } + .gate-notch.tone-warn { stroke: #ffb000; fill: color-mix(in srgb, #ffb000 30%, var(--af-bg)); filter: drop-shadow(0 0 7px rgb(255 176 0 / 0.65)); } + .gate-notch.tone-info { stroke: #22d3ee; fill: color-mix(in srgb, #22d3ee 30%, var(--af-bg)); filter: drop-shadow(0 0 7px rgb(34 211 238 / 0.65)); } + .gate-tag { font-family: var(--af-font-mono); font-size: 14px; letter-spacing: 0.08em; fill: var(--af-text-muted); text-transform: uppercase; } + .dest-pill { fill: var(--af-surface); stroke: var(--af-line); stroke-width: 1.5; } + .dest-text { font-family: var(--af-font-mono); font-size: 12px; fill: var(--af-text-muted); } + .dest-subtag { font-family: var(--af-font-mono); font-size: 9px; letter-spacing: 0.1em; fill: var(--af-text-muted); opacity: 0.7; text-transform: uppercase; } + .syscall-dot { opacity: 0; } + .gate-pulse { fill: none; opacity: 0; } + .boundary-readout { margin-top: 1.1rem; font-family: var(--af-font-mono); font-size: 0.85rem; color: var(--af-text-muted); min-height: 1.4em; } + .boundary-legend { display: flex; gap: 1.5rem; flex-wrap: wrap; margin-top: 0.9rem; font-family: var(--af-font-mono); font-size: 0.78rem; color: var(--af-text-muted); } + .boundary-legend .swatch { width: 8px; height: 8px; border-radius: 50%; display: inline-block; margin-right: 0.45rem; vertical-align: middle; } + .swatch-blocked { background: var(--af-accent); } + .swatch-allowed { background: #22d3ee; } + /* ---- Sections ---- */ section { padding: 4rem 0; border-top: 1px solid var(--af-line); } .section-head { margin-bottom: 2.25rem; max-width: 60ch; } @@ -199,15 +212,14 @@ footer a { text-decoration: underline; text-decoration-color: var(--af-line); text-underline-offset: 3px; } @media (max-width: 820px) { - .hero .wrap { grid-template-columns: 1fr; padding-top: 3rem; padding-bottom: 3rem; } + .hero .wrap { padding-top: 3rem; padding-bottom: 2rem; } + .boundary-stage { padding: 1.75rem 0 2.5rem; } .topbar-nav a[href^="#"] { display: none; } .topbar-nav { gap: 0.75rem; } } @media (max-width: 480px) { .topbar .wrap { flex-wrap: wrap; row-gap: 0.6rem; padding-top: 0.75rem; padding-bottom: 0.75rem; min-height: 0; } .topbar { min-height: 0; } - .feed-line { grid-template-columns: auto auto minmax(0, 1fr); } - .feed-line .who { display: none; } } .table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; } @@ -230,7 +242,7 @@
-
+
OS-level sandbox for AI coding agents

A trust boundary the AI can't argue its way out of.

@@ -247,21 +259,61 @@

A trust boundary the AI can't argue its way out of.

The most-starred tool in the AxeForge portfolio. See it on GitHub.

+
-
-
Live demo (simulated output, not a real sandbox)
-
-
- - aigate run -- claude -
-
-
[aigate] sandbox active
-
[aigate] deny_read: .env, secrets/, ~/.ssh/, *.pem
-
[aigate] deny_exec: curl, wget, ssh, scp
-
[aigate] allow_net: api.anthropic.com, api.github.com
+
+
+
Live demo — simulated syscalls crossing the sandbox boundary, not a real sandbox
+
+
+ + Diagram of an AI agent process enclosed by a kernel-enforced sandbox boundary. Three gates control what may cross: FILE, EXEC, and NETWORK. Allowed syscalls pass through their gate; blocked syscalls bounce back inside the boundary. + + + + + + + + + + AI agent process + claude · cursor · aider + + + + + allowed host + api.anthropic.com + + + + + File + + + + Exec + + + + Net + + + + + + + + + +
-
+
+

Every file read, command, and network call the agent makes is checked against your rules before it runs.

+
+ Blocked — kernel refuses, the process physically cannot cross + Allowed — matches an explicit rule
@@ -419,43 +471,173 @@

Three commands to a sandboxed agent

gumshoe.

+ +