Human-Agent-Interface / index.html
smlflg's picture
Initial public upload from Projekte/Human-Agent-Interface (part 4)
93828ef verified
Raw History Blame Contribute Delete
91.3 kB
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Human Agent Interface (HAI) by Samuel Fleig — Agent Control & Human Ownership</title>
<link rel="icon" type="image/png" href="/favicon.png">
<link rel="canonical" href="https://www.human-agent-interface.com/">
<meta
name="description"
content="Human Agent Interface (HAI), created by Samuel Fleig, keeps agentic AI work observable, bounded, verifiable, and human-owned."
>
<meta property="og:title" content="Human Agent Interface (HAI) by Samuel Fleig">
<meta
property="og:description"
content="An open-source approach for keeping agentic AI work observable, bounded, verifiable, and human-owned."
>
<meta property="og:type" content="website">
<meta property="og:url" content="https://www.human-agent-interface.com/">
<meta name="twitter:card" content="summary_large_image">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Person",
"@id": "https://www.human-agent-interface.com/samuel/#samuel-fleig",
"name": "Samuel Fleig",
"url": "https://www.human-agent-interface.com/samuel/",
"jobTitle": "AI Engineer",
"knowsAbout": [
"AI agents",
"agentic systems",
"AI harnesses",
"Model Context Protocol",
"human-agent interaction"
],
"sameAs": [
"https://github.com/smlfg",
"https://x.com/Samuelflg1",
"https://www.linkedin.com/in/samuel-fleig-52610914b",
"https://medium.com/@smlflg"
]
},
{
"@type": "CreativeWork",
"@id": "https://www.human-agent-interface.com/#human-agent-interface",
"name": "Human Agent Interface",
"alternateName": "HAI",
"url": "https://www.human-agent-interface.com/",
"creator": { "@id": "https://www.human-agent-interface.com/samuel/#samuel-fleig" },
"description": "Human Agent Interface (HAI) is an approach for keeping agentic AI work observable, bounded, verifiable, and human-owned.",
"subjectOf": [
{ "@id": "https://www.human-agent-interface.com/hai-mcp/#hai-mcp" },
{ "@id": "https://www.human-agent-interface.com/proof/#proof" }
]
},
{
"@type": "SoftwareSourceCode",
"@id": "https://www.human-agent-interface.com/hai-mcp/#hai-mcp",
"name": "HAI-MCP",
"codeRepository": "https://github.com/smlfg/hai-mcp",
"url": "https://www.human-agent-interface.com/hai-mcp/",
"sameAs": [
"https://github.com/smlfg/hai-mcp",
"https://glama.ai/mcp/servers/@smlfg/hai-mcp"
],
"programmingLanguage": "Python",
"creator": { "@id": "https://www.human-agent-interface.com/samuel/#samuel-fleig" },
"isPartOf": { "@id": "https://www.human-agent-interface.com/#human-agent-interface" },
"description": "HAI-MCP is the model-agnostic MCP control-plane implementation of Human Agent Interface."
}
]
}
</script>
<style>
:root {
color-scheme: dark;
--ink: #f7f1df;
--muted: #b7ad97;
--dim: #756d5e;
--void: #090a08;
--panel: rgba(247, 241, 223, 0.065);
--panel-strong: rgba(247, 241, 223, 0.13);
--line: rgba(247, 241, 223, 0.18);
--line-soft: rgba(247, 241, 223, 0.1);
--signal: #a7ff4f;
--copper: #ff9f5f;
--red: #ff4d4d;
--cyan: #7dd8ff;
--max: 1160px;
}
* {
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
margin: 0;
min-width: 320px;
color: var(--ink);
background:
radial-gradient(circle at 20% 10%, rgba(167, 255, 79, 0.12), transparent 26rem),
radial-gradient(circle at 80% 18%, rgba(255, 159, 95, 0.1), transparent 22rem),
linear-gradient(180deg, #090a08 0%, #11100d 48%, #070806 100%);
font-family: "Aptos", "Segoe UI", "Helvetica Neue", sans-serif;
line-height: 1.5;
overflow-x: hidden;
}
body::before {
content: "";
position: fixed;
inset: 0;
pointer-events: none;
z-index: 5;
opacity: 0.32;
background-image:
linear-gradient(rgba(255, 255, 255, 0.035) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.025) 1px, transparent 1px);
background-size: 72px 72px;
mask-image: linear-gradient(180deg, black, transparent 72%);
}
a {
color: inherit;
}
.site-shell {
position: relative;
z-index: 1;
}
.hero {
position: relative;
min-height: 100svh;
display: grid;
grid-template-columns: minmax(0, 1fr);
align-items: center;
overflow: hidden;
padding: 32px clamp(18px, 4vw, 56px) 48px;
}
.hero-image,
.hero-canvas {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.hero-image {
object-fit: cover;
object-position: center center;
opacity: 0.86;
}
.hero-canvas {
opacity: 0.18;
mix-blend-mode: screen;
}
.hero::after {
content: "";
position: absolute;
inset: 0;
background:
linear-gradient(90deg, rgba(9, 10, 8, 0.96) 0%, rgba(9, 10, 8, 0.86) 34%, rgba(9, 10, 8, 0.42) 68%, rgba(9, 10, 8, 0.2) 100%),
linear-gradient(180deg, rgba(9, 10, 8, 0.46) 0%, rgba(9, 10, 8, 0.2) 48%, rgba(9, 10, 8, 0.94) 100%);
pointer-events: none;
}
.nav {
position: absolute;
inset: 0 0 auto;
z-index: 12;
display: flex;
align-items: center;
justify-content: space-between;
gap: 18px;
padding: 24px clamp(18px, 4vw, 56px);
}
.nav-actions {
display: inline-flex;
align-items: center;
gap: 12px;
flex-wrap: nowrap;
justify-content: flex-end;
}
.lang-copy {
display: none;
}
.lang-copy[data-lang-copy="en"] {
display: inline;
}
html.lang-de .lang-copy[data-lang-copy="en"] {
display: none;
}
html.lang-en .lang-copy[data-lang-copy="en"],
html.lang-de .lang-copy[data-lang-copy="de"] {
display: inline;
}
.copy-block {
display: none;
}
.copy-block[data-lang-copy="en"] {
display: block;
}
html.lang-de .copy-block[data-lang-copy="en"] {
display: none;
}
html.lang-en .copy-block[data-lang-copy="en"],
html.lang-de .copy-block[data-lang-copy="de"] {
display: block;
}
.language-switch {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 3px;
border: 1px solid var(--line-soft);
background: rgba(9, 10, 8, 0.48);
}
.lang-button {
min-height: 32px;
min-width: 38px;
padding: 0 9px;
border: 0;
background: transparent;
color: var(--muted);
cursor: pointer;
font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
font-size: 0.68rem;
font-weight: 700;
text-transform: uppercase;
}
.lang-button[aria-pressed="true"] {
background: rgba(167, 255, 79, 0.14);
color: var(--ink);
}
.lang-button:hover,
.lang-button:focus-visible {
color: var(--ink);
outline: 1px solid rgba(167, 255, 79, 0.36);
outline-offset: -1px;
}
.nav-link {
min-height: 42px;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0 14px;
color: var(--muted);
font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
font-size: 0.72rem;
text-decoration: none;
text-transform: uppercase;
border: 1px solid transparent;
transition: color 180ms ease, border-color 180ms ease, background 180ms ease;
}
.nav-link:hover,
.nav-link:focus-visible {
color: var(--ink);
border-color: var(--line-soft);
background: rgba(247, 241, 223, 0.045);
}
.brand {
display: inline-flex;
align-items: center;
gap: 12px;
font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
font-size: 0.82rem;
text-transform: uppercase;
color: var(--muted);
}
.brand-mark {
width: 38px;
height: 38px;
display: grid;
place-items: center;
border: 1px solid var(--line);
background: rgba(247, 241, 223, 0.04);
color: var(--signal);
}
.nav-cta {
min-height: 42px;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0 18px;
border: 1px solid rgba(167, 255, 79, 0.44);
background: rgba(167, 255, 79, 0.09);
color: var(--ink);
text-decoration: none;
font-size: 0.86rem;
font-weight: 700;
transition: transform 180ms ease, background 180ms ease, border-color 180ms ease;
}
.nav-cta:hover,
.nav-cta:focus-visible {
transform: translateY(-2px);
background: rgba(167, 255, 79, 0.16);
border-color: rgba(167, 255, 79, 0.8);
}
.mobile-samuel-link {
display: none;
}
.hero-inner {
position: relative;
z-index: 1;
width: 100%;
max-width: var(--max);
min-width: 0;
margin: 0 auto;
padding-top: 72px;
}
.lineage {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 8px;
width: 100%;
max-width: 700px;
margin-bottom: clamp(36px, 6vw, 78px);
}
.epoch {
min-height: 92px;
padding: 14px;
display: grid;
grid-template-rows: auto auto 1fr;
gap: 8px;
border: 1px solid var(--line-soft);
background: rgba(9, 10, 8, 0.54);
backdrop-filter: blur(12px);
}
.epoch::after {
content: "";
min-height: 30px;
display: grid;
align-items: end;
color: rgba(247, 241, 223, 0.58);
font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
font-size: 0.62rem;
line-height: 1.2;
text-transform: none;
}
.epoch[data-stage="cli"]::after {
content: "$ scope --next";
}
.epoch[data-stage="tui"]::after {
content: "[1] plan\A[2] run";
white-space: pre;
}
.epoch[data-stage="gui"]::after {
content: "[ button ] [ view ]";
}
.epoch[data-stage="hai"]::after {
content: "human -> gate -> agent";
color: rgba(167, 255, 79, 0.78);
}
.epoch strong {
font-family: Georgia, "Times New Roman", serif;
font-size: clamp(1.6rem, 4vw, 3.1rem);
line-height: 0.86;
font-weight: 500;
}
.epoch span {
color: var(--dim);
font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
font-size: 0.7rem;
text-transform: uppercase;
}
.epoch.is-current {
border-color: rgba(167, 255, 79, 0.72);
background:
linear-gradient(135deg, rgba(167, 255, 79, 0.18), rgba(125, 216, 255, 0.06)),
rgba(9, 10, 8, 0.7);
box-shadow: 0 0 46px rgba(167, 255, 79, 0.14);
}
.eyebrow {
display: inline-flex;
align-items: center;
gap: 10px;
margin-bottom: 18px;
color: var(--signal);
font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
font-size: 0.76rem;
text-transform: uppercase;
}
.eyebrow::before {
content: "";
width: 44px;
height: 1px;
background: var(--signal);
}
h1 {
width: 100%;
max-width: 1040px;
margin: 0;
font-family: Georgia, "Times New Roman", serif;
font-weight: 500;
font-size: clamp(3rem, 7.6vw, 7.2rem);
line-height: 0.94;
letter-spacing: 0;
overflow-wrap: break-word;
}
.hero-copy {
display: grid;
grid-template-columns: minmax(0, 760px);
gap: 18px;
align-items: start;
margin-top: clamp(28px, 5vw, 56px);
}
.hero-copy.hero-variant,
.hero-text-variant {
display: none;
}
html:not([data-hero-variant]) .hero-copy.hero-variant[data-hero-variant="A_control"],
html[data-hero-variant="A_control"] .hero-copy.hero-variant[data-hero-variant="A_control"],
html[data-hero-variant="B_offer_first"] .hero-copy.hero-variant[data-hero-variant="B_offer_first"],
html[data-hero-variant="C_proof_first"] .hero-copy.hero-variant[data-hero-variant="C_proof_first"] {
display: grid;
}
html:not([data-hero-variant]) .hero-text-variant[data-hero-variant="A_control"],
html[data-hero-variant="A_control"] .hero-text-variant[data-hero-variant="A_control"],
html[data-hero-variant="B_offer_first"] .hero-text-variant[data-hero-variant="B_offer_first"],
html[data-hero-variant="C_proof_first"] .hero-text-variant[data-hero-variant="C_proof_first"] {
display: contents;
}
.lead {
max-width: 720px;
margin: 0;
color: var(--muted);
font-size: clamp(1.12rem, 2vw, 1.62rem);
min-width: 0;
}
.mobile-break {
display: none;
}
.desktop-break {
display: block;
}
.lead strong {
color: var(--ink);
font-weight: 700;
}
.hero-actions {
display: flex;
flex-wrap: wrap;
gap: 12px;
justify-content: flex-start;
max-width: 760px;
}
.access-router {
width: 100%;
max-width: 1120px;
margin: 0 auto;
padding: clamp(18px, 3vw, 28px);
border: 1px solid rgba(247, 241, 223, 0.2);
background: rgba(13, 14, 11, 0.82);
backdrop-filter: blur(16px);
box-shadow: 0 24px 82px rgba(0, 0, 0, 0.22);
}
.router-section {
padding-top: clamp(36px, 6vw, 82px);
background:
linear-gradient(180deg, #090a08 0%, #141511 52%, #191b15 100%);
}
.router-panel {
display: grid;
gap: 18px;
}
.js .router-panel {
display: none;
}
.js.lang-en .router-panel[data-lang="en"],
.js.lang-de .router-panel[data-lang="de"] {
display: grid;
}
.router-head {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 18px;
align-items: start;
}
.router-head h2 {
max-width: 760px;
margin: 0;
font-family: Georgia, "Times New Roman", serif;
font-size: clamp(1.72rem, 3.4vw, 3.25rem);
font-weight: 500;
line-height: 1;
letter-spacing: 0;
text-wrap: balance;
}
.router-head p:not(.eyebrow) {
max-width: 620px;
margin: 10px 0 0;
color: var(--muted);
font-size: 1rem;
}
.router-grid {
display: grid;
grid-template-columns: minmax(0, 1.12fr) minmax(0, 0.9fr);
gap: 12px;
}
.audience-card {
min-height: 270px;
display: grid;
grid-template-rows: auto auto 1fr auto auto;
gap: 12px;
padding: 20px;
border: 1px solid var(--line-soft);
background: rgba(247, 241, 223, 0.045);
}
.audience-card.is-primary {
border-color: rgba(167, 255, 79, 0.5);
background:
linear-gradient(135deg, rgba(167, 255, 79, 0.13), rgba(125, 216, 255, 0.055)),
rgba(247, 241, 223, 0.05);
}
.route-label {
color: var(--copper);
font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
font-size: 0.72rem;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.audience-card h3 {
margin: 0;
color: var(--ink);
font-family: Georgia, "Times New Roman", serif;
font-size: clamp(1.55rem, 2.7vw, 2.45rem);
font-weight: 500;
line-height: 1.02;
letter-spacing: 0;
}
.audience-card p {
margin: 0;
color: var(--muted);
font-size: 0.98rem;
}
.route-tags {
display: flex;
flex-wrap: wrap;
gap: 7px;
}
.route-tags span {
min-height: 26px;
display: inline-flex;
align-items: center;
padding: 0 9px;
border: 1px solid rgba(247, 241, 223, 0.16);
color: var(--muted);
font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
font-size: 0.65rem;
text-transform: uppercase;
}
.route-actions {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.button {
min-height: 52px;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 10px;
padding: 0 22px;
border: 1px solid var(--line);
background: var(--panel);
color: var(--ink);
text-decoration: none;
font-weight: 800;
transition: transform 180ms ease, background 180ms ease, border-color 180ms ease;
}
.button.primary {
border-color: rgba(167, 255, 79, 0.68);
background: var(--signal);
color: #11150d;
}
.button:hover,
.button:focus-visible {
transform: translateY(-2px);
border-color: rgba(247, 241, 223, 0.42);
background: var(--panel-strong);
}
.button.primary:hover,
.button.primary:focus-visible {
border-color: var(--signal);
background: #c4ff86;
}
.section {
padding: clamp(70px, 10vw, 150px) clamp(18px, 4vw, 56px);
}
.section-smoke {
background:
linear-gradient(180deg, rgba(247, 241, 223, 0.055), rgba(247, 241, 223, 0.018)),
#141511;
}
.section-inner {
width: 100%;
max-width: var(--max);
margin: 0 auto;
}
.split {
display: grid;
grid-template-columns: minmax(0, 0.82fr) minmax(280px, 0.58fr);
gap: clamp(28px, 6vw, 90px);
align-items: start;
}
h2 {
margin: 0;
font-family: Georgia, "Times New Roman", serif;
font-size: clamp(2.4rem, 6vw, 5.8rem);
line-height: 0.98;
font-weight: 500;
letter-spacing: 0;
}
.kicker {
margin: 0 0 16px;
color: var(--copper);
font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
font-size: 0.78rem;
text-transform: uppercase;
}
.body-copy {
margin: 0;
color: var(--muted);
font-size: clamp(1.02rem, 1.7vw, 1.28rem);
}
.body-copy + .body-copy {
margin-top: 20px;
}
.fit-call {
border-block: 1px solid var(--line-soft);
background:
linear-gradient(180deg, rgba(167, 255, 79, 0.055), rgba(247, 241, 223, 0.015)),
#0b0c09;
}
.fit-call-grid {
display: grid;
grid-template-columns: minmax(0, 0.86fr) minmax(300px, 0.52fr);
gap: clamp(28px, 6vw, 90px);
align-items: start;
}
.fit-hook {
max-width: 680px;
}
.intake-list {
display: grid;
gap: 10px;
margin-top: 30px;
counter-reset: intake;
}
.intake-question {
min-height: 92px;
display: grid;
grid-template-columns: 44px 1fr;
gap: 14px;
padding: 16px;
border: 1px solid var(--line-soft);
background: rgba(247, 241, 223, 0.045);
counter-increment: intake;
}
.intake-question::before {
content: "0" counter(intake);
color: var(--signal);
font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
font-size: 0.78rem;
}
.intake-question strong {
display: block;
color: var(--ink);
font-size: 1.02rem;
}
.intake-question span {
display: block;
margin-top: 6px;
color: var(--muted);
font-size: 0.95rem;
}
.pilot-note {
margin-top: 22px;
padding: 16px 0 0 16px;
border-left: 2px solid rgba(167, 255, 79, 0.62);
color: var(--muted);
font-size: 1rem;
}
.output-panel {
padding: clamp(22px, 4vw, 30px);
border: 1px solid var(--line);
background:
linear-gradient(135deg, rgba(247, 241, 223, 0.08), rgba(247, 241, 223, 0.025)),
rgba(9, 10, 8, 0.58);
}
.output-panel h3 {
margin: 18px 0 14px;
color: var(--ink);
font-family: Georgia, "Times New Roman", serif;
font-size: clamp(2rem, 4vw, 3.45rem);
line-height: 0.98;
font-weight: 500;
}
.output-panel p {
margin: 0;
color: var(--muted);
font-size: 1rem;
}
.output-list {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 8px;
margin: 24px 0 0;
padding: 0;
list-style: none;
}
.output-list li {
min-height: 46px;
display: flex;
align-items: center;
padding: 10px 12px;
border: 1px solid var(--line-soft);
color: var(--ink);
background: rgba(247, 241, 223, 0.04);
font-size: 0.94rem;
}
.trust-bridge {
margin-top: 22px;
padding-top: 18px;
border-top: 1px solid var(--line);
}
.fit-actions {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-top: 24px;
}
.quote-rail {
display: grid;
gap: 12px;
}
.quote-tile {
min-height: 112px;
padding: 20px;
display: grid;
align-content: space-between;
gap: 18px;
border-left: 2px solid var(--line);
background: linear-gradient(90deg, rgba(247, 241, 223, 0.08), rgba(247, 241, 223, 0.025));
}
.quote-tile strong {
display: block;
font-family: Georgia, "Times New Roman", serif;
font-size: clamp(1.3rem, 2.7vw, 2.25rem);
line-height: 1;
font-weight: 500;
}
.quote-tile span {
color: var(--dim);
font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
font-size: 0.72rem;
text-transform: uppercase;
}
.quote-tile:nth-child(2) {
border-left-color: var(--red);
}
.quote-tile:nth-child(3) {
border-left-color: var(--signal);
}
.conversion {
background:
linear-gradient(180deg, rgba(247, 241, 223, 0.04), rgba(247, 241, 223, 0.01)),
#0c0d0a;
border-block: 1px solid var(--line-soft);
}
.conversion-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
margin-top: 36px;
}
.state {
min-height: 360px;
padding: clamp(20px, 4vw, 34px);
border: 1px solid var(--line-soft);
background: rgba(247, 241, 223, 0.045);
position: relative;
overflow: hidden;
}
.state::before {
content: "";
position: absolute;
inset: 0;
opacity: 0.26;
background-image: linear-gradient(135deg, transparent 0 46%, currentColor 47% 48%, transparent 49% 100%);
background-size: 34px 34px;
}
.state.before {
color: rgba(255, 77, 77, 0.8);
}
.state.after {
color: rgba(167, 255, 79, 0.74);
}
.state-content {
position: relative;
z-index: 1;
}
.state-label {
color: var(--dim);
font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
font-size: 0.78rem;
text-transform: uppercase;
}
.state h3 {
margin: 18px 0 26px;
color: var(--ink);
font-family: Georgia, "Times New Roman", serif;
font-size: clamp(2rem, 4.2vw, 4.2rem);
line-height: 0.98;
font-weight: 500;
}
.state ul {
margin: 0;
padding: 0;
list-style: none;
display: grid;
gap: 12px;
color: var(--muted);
font-size: 1rem;
}
.state li {
display: grid;
grid-template-columns: 18px 1fr;
gap: 10px;
align-items: start;
}
.state li::before {
content: "";
width: 9px;
height: 9px;
margin-top: 8px;
background: currentColor;
}
.method-grid {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 10px;
margin-top: 46px;
}
.step {
min-height: 210px;
padding: 18px;
border: 1px solid var(--line-soft);
background: rgba(247, 241, 223, 0.04);
}
.step span {
color: var(--signal);
font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
font-size: 0.75rem;
}
.step h3 {
margin: 54px 0 12px;
color: var(--ink);
font-family: Georgia, "Times New Roman", serif;
font-size: 1.55rem;
line-height: 1.05;
font-weight: 500;
}
.step p {
margin: 0;
color: var(--muted);
font-size: 0.95rem;
}
.wide-statement {
padding: clamp(70px, 10vw, 140px) clamp(18px, 4vw, 56px);
background:
linear-gradient(180deg, #d7d0bc 0%, #f7f1df 100%);
color: #10110d;
}
.wide-statement .section-inner {
display: grid;
grid-template-columns: minmax(0, 0.78fr) minmax(280px, 0.42fr);
gap: clamp(26px, 5vw, 72px);
align-items: end;
}
.wide-statement p {
margin: 0;
color: rgba(16, 17, 13, 0.72);
font-size: clamp(1rem, 1.7vw, 1.32rem);
}
.tool-line {
margin: 0;
font-family: Georgia, "Times New Roman", serif;
font-size: clamp(2.5rem, 7vw, 6.8rem);
line-height: 0.96;
font-weight: 500;
letter-spacing: 0;
}
.authority-teaser {
border-block: 1px solid var(--line-soft);
background:
linear-gradient(180deg, rgba(247, 241, 223, 0.035), rgba(247, 241, 223, 0.01)),
#0d0e0b;
}
.authority-grid {
display: grid;
grid-template-columns: minmax(0, 0.82fr) minmax(280px, 0.58fr);
gap: clamp(28px, 6vw, 90px);
align-items: end;
}
.authority-panel {
padding: 24px;
border-left: 1px solid var(--line);
background: linear-gradient(90deg, rgba(247, 241, 223, 0.07), transparent);
}
.authority-panel span {
display: block;
margin-bottom: 14px;
color: var(--signal);
font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
font-size: 0.72rem;
text-transform: uppercase;
}
.authority-panel p {
margin: 0 0 22px;
color: var(--muted);
font-size: 1.05rem;
}
.contact {
min-height: 72svh;
display: grid;
align-items: center;
}
.contact-panel {
display: grid;
grid-template-columns: minmax(0, 0.8fr) minmax(280px, 0.52fr);
gap: clamp(24px, 6vw, 88px);
align-items: center;
}
.contact-note {
border-top: 1px solid var(--line);
padding-top: 22px;
}
.contact-note p {
margin: 0;
color: var(--muted);
font-size: 1.05rem;
}
footer {
padding: 28px clamp(18px, 4vw, 56px);
color: var(--dim);
font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
font-size: 0.72rem;
text-transform: uppercase;
border-top: 1px solid var(--line-soft);
}
footer .section-inner {
display: flex;
justify-content: space-between;
gap: 14px;
flex-wrap: wrap;
}
.reveal {
opacity: 1;
transform: translateY(0);
transition: opacity 700ms ease, transform 700ms ease;
}
.js .reveal.is-visible {
opacity: 1;
transform: translateY(0);
}
@media (max-width: 900px) {
.hero {
min-height: auto;
padding-top: 116px;
}
.hero-image {
object-position: 58% center;
opacity: 0.72;
}
.hero::after {
background:
linear-gradient(90deg, rgba(9, 10, 8, 0.95) 0%, rgba(9, 10, 8, 0.76) 72%, rgba(9, 10, 8, 0.52) 100%),
linear-gradient(180deg, rgba(9, 10, 8, 0.56) 0%, rgba(9, 10, 8, 0.36) 38%, rgba(9, 10, 8, 0.96) 100%);
}
.hero-copy,
.router-head,
.router-grid,
.split,
.fit-call-grid,
.authority-grid,
.wide-statement .section-inner,
.contact-panel {
grid-template-columns: 1fr;
}
.conversion-grid {
grid-template-columns: 1fr;
}
.method-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 620px) {
.hero {
width: 100vw;
padding-left: 20px;
padding-right: 20px;
}
.nav {
padding-top: 18px;
width: 100vw;
left: 0;
right: auto;
padding-left: 20px;
padding-right: 20px;
}
.brand span:not(.brand-mark) {
display: none;
}
.nav-cta {
display: none;
}
.nav-actions {
display: inline-flex;
gap: 8px;
max-width: calc(100vw - 92px);
}
.desktop-nav-link {
display: none;
}
.nav-link {
min-height: 36px;
padding: 0 10px;
font-size: 0.62rem;
}
.mobile-samuel-link {
min-height: 36px;
display: inline-flex;
align-items: center;
justify-content: center;
margin-left: auto;
padding: 0 10px;
border: 1px solid var(--line-soft);
color: var(--muted);
font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
font-size: 0.62rem;
text-decoration: none;
text-transform: uppercase;
}
.hero-inner,
.lineage,
h1,
.access-router,
.hero-copy,
.lead {
width: 350px;
max-width: calc(100vw - 40px);
}
.hero-inner {
margin-left: 0;
margin-right: 0;
padding-top: 0;
}
.lineage {
grid-template-columns: repeat(2, minmax(0, 1fr));
margin-bottom: 24px;
}
.epoch {
min-height: 68px;
}
h1 {
font-size: clamp(2.35rem, 11.5vw, 3.1rem);
line-height: 0.98;
}
.lead {
font-size: 1rem;
}
.mobile-break {
display: block;
}
.desktop-break {
display: inline;
}
.method-grid {
grid-template-columns: 1fr;
}
.step {
min-height: 170px;
}
.step h3 {
margin-top: 30px;
}
.button {
width: 100%;
}
.intake-question,
.output-list {
grid-template-columns: 1fr;
}
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.001ms !important;
animation-iteration-count: 1 !important;
scroll-behavior: auto !important;
transition-duration: 0.001ms !important;
}
}
</style>
</head>
<body>
<main class="site-shell">
<section class="hero" aria-labelledby="hero-title">
<img class="hero-image" src="assets/hai-interface-background.webp" width="1672" height="941" alt="" aria-hidden="true">
<canvas class="hero-canvas" id="agentField" aria-hidden="true"></canvas>
<nav class="nav" aria-label="Main navigation">
<a class="brand" href="#top" aria-label="Human Agent Interface home">
<span class="brand-mark">HAI</span>
<span>Human Agent Interface</span>
</a>
<a class="mobile-samuel-link" href="./samuel/">
<span class="lang-copy" data-lang-copy="en">Samuel</span>
<span class="lang-copy" data-lang-copy="de">Samuel</span>
</a>
<div class="nav-actions">
<a class="nav-link desktop-nav-link" href="./what_it_is/">
<span class="lang-copy" data-lang-copy="en">Method</span>
<span class="lang-copy" data-lang-copy="de">Methode</span>
</a>
<a class="nav-link desktop-nav-link" href="./proof/">
<span class="lang-copy" data-lang-copy="en">Proof</span>
<span class="lang-copy" data-lang-copy="de">Nachweis</span>
</a>
<a class="nav-link desktop-nav-link" href="./samuel/">Samuel</a>
<a class="nav-link desktop-nav-link" href="./hai-mcp/">HAI-MCP</a>
<a class="nav-link desktop-nav-link" href="./product/">
<span class="lang-copy" data-lang-copy="en">Offer</span>
<span class="lang-copy" data-lang-copy="de">Angebot</span>
</a>
<div class="language-switch" aria-label="Language">
<button class="lang-button" type="button" data-lang-toggle="de" aria-pressed="false">DE</button>
<button class="lang-button" type="button" data-lang-toggle="en" aria-pressed="false">EN</button>
</div>
<a
class="nav-cta"
data-site-event="cta_click"
data-event-target="nav_fit_call"
href="mailto:samuel@human-agent-interface.com?subject=20%20min%20HAI%20fit%20call&amp;body=Hi%20Samuel%2C%0D%0A%0D%0AI%20want%20to%20book%20a%2020%20min%20HAI%20fit%20call.%0D%0A%0D%0A1.%20What%20agent%20workflow%20is%20creating%20confusion%3F%0D%0A%0D%0A2.%20Where%20do%20I%20lose%20control%2C%20overview%2C%20or%20trust%3F%0D%0A%0D%0A3.%20What%20would%20be%20useful%20after%204%20hours%3F%0D%0A%0D%0APreferred%20time%20windows%3A"
>
<span class="lang-copy" data-lang-copy="en">Test fit call</span>
<span class="lang-copy" data-lang-copy="de">Fit-Call testen</span>
</a>
</div>
</nav>
<div class="hero-inner" id="top">
<div class="lineage reveal" aria-label="Interface evolution">
<div class="epoch" data-stage="cli">
<strong>CLI</strong>
<span>
<span class="lang-copy" data-lang-copy="en">commands</span>
<span class="lang-copy" data-lang-copy="de">Befehle</span>
</span>
</div>
<div class="epoch" data-stage="tui">
<strong>TUI</strong>
<span>terminal</span>
</div>
<div class="epoch" data-stage="gui">
<strong>GUI</strong>
<span>
<span class="lang-copy" data-lang-copy="en">screens</span>
<span class="lang-copy" data-lang-copy="de">Oberflächen</span>
</span>
</div>
<div class="epoch is-current" data-stage="hai">
<strong>HAI</strong>
<span>
<span class="lang-copy" data-lang-copy="en">agency</span>
<span class="lang-copy" data-lang-copy="de">Kontrolle</span>
</span>
</div>
</div>
<p class="eyebrow reveal">
<span class="hero-text-variant" data-hero-variant="A_control">
<span class="lang-copy" data-lang-copy="en">For people stuck inside agent threads</span>
<span class="lang-copy" data-lang-copy="de">Für Menschen in zu vielen Agenten-Threads</span>
</span>
<span class="hero-text-variant" data-hero-variant="B_offer_first">
<span class="lang-copy" data-lang-copy="en">For one messy agent workflow</span>
<span class="lang-copy" data-lang-copy="de">Für einen chaotischen Agenten-Workflow</span>
</span>
<span class="hero-text-variant" data-hero-variant="C_proof_first">
<span class="lang-copy" data-lang-copy="en">Proof before more agent output</span>
<span class="lang-copy" data-lang-copy="de">Nachweis vor noch mehr Agenten-Output</span>
</span>
</p>
<h1 class="reveal" id="hero-title">
<span class="hero-text-variant" data-hero-variant="A_control">
<span class="lang-copy" data-lang-copy="en">
AI work should create momentum.
<span class="desktop-break"></span>
For most people, it creates confusion.
</span>
<span class="lang-copy" data-lang-copy="de">
KI-Arbeit sollte Schwung geben.
<span class="desktop-break"></span>
Oft macht sie erst mehr Chaos.
</span>
</span>
<span class="hero-text-variant" data-hero-variant="B_offer_first">
<span class="lang-copy" data-lang-copy="en">
Bring one chaotic agent workflow.
<span class="desktop-break"></span>
Leave with one concrete next action packet.
</span>
<span class="lang-copy" data-lang-copy="de">
Bring einen chaotischen Agenten-Workflow.
<span class="desktop-break"></span>
Geh mit einem prüfbaren nächsten Schritt.
</span>
</span>
<span class="hero-text-variant" data-hero-variant="C_proof_first">
<span class="lang-copy" data-lang-copy="en">
The problem is not stronger agents.
<span class="desktop-break"></span>
It is whether the human can still own the work.
</span>
<span class="lang-copy" data-lang-copy="de">
Das Problem sind nicht stärkere Agents.
<span class="desktop-break"></span>
Es ist, ob der Mensch die Arbeit noch besitzt.
</span>
</span>
</h1>
<div class="hero-copy hero-variant" data-hero-variant="A_control">
<p class="lead reveal">
<span class="copy-block" data-lang-copy="en">
<strong>Human Agent Interface (HAI)</strong>, created by <a href="./samuel/">Samuel Fleig</a>, turns agent chaos into work a human can still own: observable, bounded, verifiable, and human-owned.
</span>
<span class="copy-block" data-lang-copy="de">
<strong>Human Agent Interface (HAI)</strong>, entwickelt von <a href="./samuel/">Samuel Fleig</a>, macht aus Agenten-Chaos wieder Arbeit, die ein Mensch steuern kann: beobachtbar, begrenzt, überprüfbar und menschlich verantwortet.
</span>
</p>
<p class="reveal">
<span class="copy-block" data-lang-copy="en">
You have Claude Code open.<br>
Codex produced another plan.<br>
One chat says the build is done.<br>
Another says the architecture is wrong.<br>
You have five outputs and no decision.<br>
That is where HAI starts.
</span>
<span class="copy-block" data-lang-copy="de">
Claude Code ist offen.<br>
Codex hat den nächsten Plan geschrieben.<br>
Ein Chat sagt: fertig.<br>
Ein anderer sagt: Architektur falsch.<br>
Du hast fünf Outputs und keine Entscheidung.<br>
Genau dort startet HAI.
</span>
</p>
<div class="hero-actions reveal">
<a
class="button primary"
data-site-event="cta_click"
data-event-target="hero_fit_call"
href="mailto:samuel@human-agent-interface.com?subject=20%20min%20HAI%20fit%20call&amp;body=Hi%20Samuel%2C%0D%0A%0D%0AI%20want%20to%20book%20a%2020%20min%20HAI%20fit%20call.%0D%0A%0D%0A1.%20What%20agent%20workflow%20is%20creating%20confusion%3F%0D%0A%0D%0A2.%20Where%20do%20I%20lose%20control%2C%20overview%2C%20or%20trust%3F%0D%0A%0D%0A3.%20What%20would%20be%20useful%20after%204%20hours%3F%0D%0A%0D%0APreferred%20time%20windows%3A"
>
<span class="lang-copy" data-lang-copy="en">Test 20 min fit call</span>
<span class="lang-copy" data-lang-copy="de">20-Min-Fit-Call testen</span>
</a>
<a class="button" data-site-event="cta_click" data-event-target="hero_choose_path" href="#choose-path">
<span class="lang-copy" data-lang-copy="en">Choose your path</span>
<span class="lang-copy" data-lang-copy="de">Pfad wählen</span>
</a>
<a class="button" data-site-event="cta_click" data-event-target="hero_proof" href="./proof/">
<span class="lang-copy" data-lang-copy="en">Proof</span>
<span class="lang-copy" data-lang-copy="de">Nachweis</span>
</a>
</div>
</div>
<div class="hero-copy hero-variant" data-hero-variant="B_offer_first">
<p class="lead reveal">
<span class="copy-block" data-lang-copy="en">
<strong>HAI starts with one workflow you can actually inspect.</strong> Bring the messy agent thread, stalled tool run, or pile of conflicting plans. Leave with a scoped packet: what the agent does, what you decide, and how the work gets verified.
</span>
<span class="copy-block" data-lang-copy="de">
<strong>HAI startet mit einem Workflow, den du wirklich prüfen kannst.</strong> Bring den verworrenen Agenten-Thread, den steckenden Tool-Run oder die widersprüchlichen Pläne. Am Ende steht ein kleiner Scope: was der Agent tut, was du entscheidest und wie die Arbeit geprüft wird.
</span>
</p>
<div class="hero-actions reveal">
<a
class="button primary"
data-site-event="cta_click"
data-event-target="hero_fit_call"
href="mailto:samuel@human-agent-interface.com?subject=One%20messy%20agent%20workflow&amp;body=Hi%20Samuel%2C%0D%0A%0D%0AI%20want%20to%20bring%20one%20messy%20agent%20workflow%20and%20turn%20it%20into%20a%20clear%20next%20action%20packet.%0D%0A%0D%0AWhat%20is%20currently%20chaotic%3A%0D%0A%0D%0ATools%20involved%3A%0D%0A%0D%0AWhat%20I%20need%20to%20decide%3A%0D%0A%0D%0APreferred%20time%20windows%3A"
>
<span class="lang-copy" data-lang-copy="en">Bring one workflow</span>
<span class="lang-copy" data-lang-copy="de">Einen Workflow mitbringen</span>
</a>
<a class="button" data-site-event="cta_click" data-event-target="hero_product" href="./product/">
<span class="lang-copy" data-lang-copy="en">See offer</span>
<span class="lang-copy" data-lang-copy="de">Angebot ansehen</span>
</a>
<a class="button" data-site-event="cta_click" data-event-target="hero_fit" href="./fit/">
<span class="lang-copy" data-lang-copy="en">Human Fit</span>
<span class="lang-copy" data-lang-copy="de">Fit prüfen</span>
</a>
</div>
</div>
<div class="hero-copy hero-variant" data-hero-variant="C_proof_first">
<p class="lead reveal">
<span class="copy-block" data-lang-copy="en">
<strong>HAI is built from real local agent systems, evals, and owner-control artifacts.</strong> The point is not to worship stronger tools. The point is whether the human can still inspect, stop, verify, and own the work.
</span>
<span class="copy-block" data-lang-copy="de">
<strong>HAI kommt aus echten lokalen Agenten-Systemen, Evals und Owner-Control-Artefakten.</strong> Es geht nicht darum, stärkere Tools zu feiern. Es geht darum, ob der Mensch Arbeit noch prüfen, stoppen, verifizieren und besitzen kann.
</span>
</p>
<div class="hero-actions reveal">
<a class="button primary" data-site-event="cta_click" data-event-target="hero_proof" href="./proof/">
<span class="lang-copy" data-lang-copy="en">See proof</span>
<span class="lang-copy" data-lang-copy="de">Nachweis ansehen</span>
</a>
<a
class="button"
data-site-event="cta_click"
data-event-target="hero_fit_call"
href="mailto:samuel@human-agent-interface.com?subject=20%20min%20HAI%20fit%20call&amp;body=Hi%20Samuel%2C%0D%0A%0D%0AI%20want%20to%20book%20a%2020%20min%20HAI%20fit%20call.%0D%0A%0D%0A1.%20What%20agent%20workflow%20is%20creating%20confusion%3F%0D%0A%0D%0A2.%20Where%20do%20I%20lose%20control%2C%20overview%2C%20or%20trust%3F%0D%0A%0D%0A3.%20What%20would%20be%20useful%20after%204%20hours%3F%0D%0A%0D%0APreferred%20time%20windows%3A"
>
<span class="lang-copy" data-lang-copy="en">Test fit call</span>
<span class="lang-copy" data-lang-copy="de">Fit-Call testen</span>
</a>
<a class="button" data-site-event="cta_click" data-event-target="hero_product" href="./product/">
<span class="lang-copy" data-lang-copy="en">See offer</span>
<span class="lang-copy" data-lang-copy="de">Angebot ansehen</span>
</a>
</div>
</div>
</div>
</section>
<section class="section router-section" aria-labelledby="choose-path">
<div class="access-router reveal" id="choose-path" aria-label="Language and audience router">
<section class="router-panel" data-lang="en" aria-labelledby="router-title-en">
<div class="router-head">
<div>
<p class="eyebrow">Language and audience routing</p>
<h2 id="router-title-en">Start where your workflow actually is.</h2>
<p>
HAI is built for agent-native work. If you are not there yet, use the simpler
door without turning HAI into beginner AI training.
</p>
</div>
<div class="language-switch" aria-label="Language">
<button class="lang-button" type="button" data-lang-toggle="de" aria-pressed="false">DE</button>
<button class="lang-button" type="button" data-lang-toggle="en" aria-pressed="false">EN</button>
</div>
</div>
<div class="router-grid">
<article class="audience-card is-primary">
<span class="route-label">Primary path / agent-native</span>
<h3>I already work with agents.</h3>
<p>
You use Claude Code, Codex, Cursor, Hermes, custom harnesses, or repeated
agent workflows. The problem is not access. It is scope, trust, verification,
ownership, and where the human must stay in control.
</p>
<div class="route-tags" aria-label="Agent-native topics">
<span>Terminal agents</span>
<span>Verification</span>
<span>Human gates</span>
<span>Adminspace</span>
</div>
<div class="route-actions">
<a class="button primary" data-site-event="cta_click" data-event-target="router_agent_workflow" href="mailto:samuel@human-agent-interface.com?subject=Agent-native%20HAI%20fit%20call&amp;body=Hi%20Samuel%2C%0D%0A%0D%0AI%20already%20work%20with%20agents%20and%20want%20to%20scope%20one%20workflow.%0D%0A%0D%0AWhere%20control%20breaks%3A%0D%0A%0D%0ATools%20I%20use%3A%0D%0A%0D%0APreferred%20time%20windows%3A">Bring one agent workflow</a>
<a class="button" data-site-event="cta_click" data-event-target="hero_product" href="./product/">See agent-native offers</a>
</div>
</article>
<article class="audience-card">
<span class="route-label">Entry path / non-agentic</span>
<h3>I need to understand AI work before I delegate more.</h3>
<p>
You are not buying a beginner course. You need language, boundaries, and a
safe first diagnostic so confusing AI work becomes one clear next step.
</p>
<div class="route-tags" aria-label="Non-agentic entry topics">
<span>Orientation</span>
<span>Trust</span>
<span>Boundaries</span>
<span>Diagnostic</span>
</div>
<div class="route-actions">
<a class="button" data-site-event="cta_click" data-event-target="router_orientation" href="mailto:samuel@human-agent-interface.com?subject=HAI%20orientation%20call&amp;body=Hi%20Samuel%2C%0D%0A%0D%0AI%20am%20not%20agent-native%20yet%2C%20but%20I%20want%20to%20understand%20how%20to%20use%20AI%20work%20without%20losing%20control.%0D%0A%0D%0AWhere%20I%20feel%20confused%3A%0D%0A%0D%0AWhat%20I%20want%20to%20decide%20next%3A">Ask for orientation</a>
<a class="button" data-site-event="cta_click" data-event-target="router_muenztelefon" href="./M%C3%BCnztelfon/">Start small: Muenztelefon diagnostic</a>
</div>
</article>
</div>
</section>
<section class="router-panel" data-lang="de" aria-labelledby="router-title-de">
<div class="router-head">
<div>
<p class="eyebrow">Sprache und Einstieg</p>
<h2 id="router-title-de">Was ist gerade chaotisch?</h2>
<p>
Nicht noch mehr Output. Erst wieder Überblick: Wo kann ich Kontrolle, Überblick oder Vertrauen verlieren?
Und was passiert mit meinem mentalen Modell des Projekts?
</p>
</div>
<div class="language-switch" aria-label="Sprache">
<button class="lang-button" type="button" data-lang-toggle="de" aria-pressed="false">DE</button>
<button class="lang-button" type="button" data-lang-toggle="en" aria-pressed="false">EN</button>
</div>
</div>
<div class="router-grid">
<article class="audience-card is-primary">
<span class="route-label">Kernpfad / agentisches Kopfweh</span>
<h3>Ich arbeite schon mit Agents, aber es wird zu viel.</h3>
<p>
Es ist zu viel Output, aber keine Entscheidung: Claude Code ist offen, Codex
plant weiter, drei Chats widersprechen sich, und am Ende musst du trotzdem
entscheiden. Agenten dürfen arbeiten, aber sie dürfen mir nicht das Projekt aus der Hand nehmen.
HAI macht daraus: ein kleiner, prüfbarer nächster Schritt.
</p>
<div class="route-tags" aria-label="Agent-native Themen">
<span>Zu viel Output</span>
<span>Keine Entscheidung</span>
<span>Prüfbarer Schritt</span>
<span>Projekt behalten</span>
</div>
<div class="route-actions">
<a class="button primary" data-site-event="cta_click" data-event-target="router_agent_workflow" href="mailto:samuel@human-agent-interface.com?subject=Agent-native%20HAI%20Fit-Call&amp;body=Hallo%20Samuel%2C%0D%0A%0D%0AIch%20arbeite%20schon%20mit%20Agents%20und%20will%20einen%20Workflow%20sauber%20scopen.%0D%0A%0D%0AWo%20Kontrolle%20bricht%3A%0D%0A%0D%0ATools%2C%20die%20ich%20nutze%3A%0D%0A%0D%0AMoegliche%20Zeiten%3A">Einen chaotischen Agent-Workflow mitbringen</a>
<a class="button" data-site-event="cta_click" data-event-target="hero_product" href="./product/">Angebote ansehen</a>
</div>
</article>
<article class="audience-card">
<span class="route-label">Eingang / erst Orientierung</span>
<h3>Ich will verstehen, was ich an KI abgeben kann, und was nicht.</h3>
<p>
Das ist kein KI-Einsteigerkurs. Es geht darum, Kontrolle, Vertrauen und Grenzen
zu finden, bevor du mehr an Tools oder Agents delegierst. Münztelefon ist für Leute, die nicht lesen wollen oder gerade überfordert sind.
</p>
<div class="route-tags" aria-label="Non-agentic Einstiegsthemen">
<span>Was abgeben?</span>
<span>Was behalten?</span>
<span>Was entscheiden?</span>
<span>Grenzen</span>
</div>
<div class="route-actions">
<a class="button" data-site-event="cta_click" data-event-target="router_orientation" href="mailto:samuel@human-agent-interface.com?subject=HAI%20Orientierung&amp;body=Hallo%20Samuel%2C%0D%0A%0D%0AIch%20bin%20noch%20nicht%20agent-native%2C%20will%20aber%20KI-Arbeit%20nutzen%2C%20ohne%20Kontrolle%20zu%20verlieren.%0D%0A%0D%0AWo%20ich%20gerade%20unsicher%20bin%3A%0D%0A%0D%0AWas%20ich%20als%20naechstes%20entscheiden%20will%3A">Orientierung anfragen</a>
<a class="button" data-site-event="cta_click" data-event-target="router_muenztelefon" href="./M%C3%BCnztelfon/">Keine Lust zu lesen: Münztelefon starten</a>
</div>
</article>
</div>
</section>
</div>
</section>
<section class="section section-smoke" aria-labelledby="confusion-title">
<div class="section-inner split">
<div>
<p class="kicker reveal">
<span class="lang-copy" data-lang-copy="en">The customer pain</span>
<span class="lang-copy" data-lang-copy="de">Der eigentliche Schmerz</span>
</p>
<h2 class="reveal" id="confusion-title">
<span class="copy-block" data-lang-copy="en">AI work creates more confusion than momentum.</span>
<span class="copy-block" data-lang-copy="de">KI-Arbeit erzeugt oft mehr Unklarheit als Schwung.</span>
</h2>
</div>
<div>
<p class="body-copy reveal">
<span class="copy-block" data-lang-copy="en">
You start with an idea, open three chats, ask for a plan, launch an agent,
paste context into another tool, then lose the thread. The output is not
wrong. It is just not owned.
</span>
<span class="copy-block" data-lang-copy="de">
Du startest mit einer Idee, öffnest drei Chats, holst einen Plan, startest einen Agenten,
kopierst Kontext in das nächste Tool und verlierst den Faden. Der Output ist nicht
unbedingt falsch. Er gehört dir nur nicht mehr richtig.
</span>
</p>
<p class="body-copy reveal">
<span class="copy-block" data-lang-copy="en">
HAI exists for that moment: when the human state is messy, the agents are
loud, and the next responsible action is not obvious.
</span>
<span class="copy-block" data-lang-copy="de">
HAI ist für genau diesen Moment da: Der menschliche Zustand ist unordentlich,
die Agents produzieren weiter, und die nächste verantwortliche Handlung ist nicht klar.
</span>
</p>
</div>
</div>
</section>
<section class="section fit-call" id="fit-call" aria-labelledby="fit-call-title">
<div class="section-inner fit-call-grid">
<div class="fit-hook">
<p class="kicker reveal">
<span class="lang-copy" data-lang-copy="en">20 min HAI fit call</span>
<span class="lang-copy" data-lang-copy="de">20-Minuten-Hypothese</span>
</p>
<h2 class="reveal" id="fit-call-title">
<span class="copy-block" data-lang-copy="en">Where do you lose control in your agent workflow?</span>
<span class="copy-block" data-lang-copy="de">Wo verlierst du Kontrolle in deinem Agenten-Workflow?</span>
</h2>
<p class="body-copy reveal">
<span class="copy-block" data-lang-copy="en">
Bring one real workflow, not a transformation plan. The call is for finding
whether HAI can turn your current agent mess into a bounded 4h audit.
</span>
<span class="copy-block" data-lang-copy="de">
Bring einen echten Workflow, keinen Transformationsplan. Der Call testet nur,
ob HAI aus deinem aktuellen Agenten-Durcheinander einen begrenzten 4h-Scope machen kann.
</span>
</p>
<div class="intake-list reveal" aria-label="Mini intake questions">
<div class="intake-question">
<div>
<strong>
<span class="lang-copy" data-lang-copy="en">What agent workflow is creating confusion?</span>
<span class="lang-copy" data-lang-copy="de">Welcher Agenten-Workflow erzeugt gerade Verwirrung?</span>
</strong>
<span>
<span class="lang-copy" data-lang-copy="en">Which chats, tools, agents, handoffs, or projects are involved?</span>
<span class="lang-copy" data-lang-copy="de">Welche Chats, Tools, Agents, Übergaben oder Projekte hängen daran?</span>
</span>
</div>
</div>
<div class="intake-question">
<div>
<strong>
<span class="lang-copy" data-lang-copy="en">Where do you lose control, overview, or trust?</span>
<span class="lang-copy" data-lang-copy="de">Wo verlierst du Kontrolle, Überblick oder Vertrauen?</span>
</strong>
<span>
<span class="lang-copy" data-lang-copy="en">Name the point where output keeps growing but ownership gets weaker.</span>
<span class="lang-copy" data-lang-copy="de">Benenne den Punkt, an dem Output wächst, aber Ownership schwächer wird.</span>
</span>
</div>
</div>
<div class="intake-question">
<div>
<strong>
<span class="lang-copy" data-lang-copy="en">What would be useful after 4 hours?</span>
<span class="lang-copy" data-lang-copy="de">Was wäre nach 4 Stunden wirklich nützlich?</span>
</strong>
<span>
<span class="lang-copy" data-lang-copy="en">A clearer setup, a stop rule, a verifier path, or one next action packet.</span>
<span class="lang-copy" data-lang-copy="de">Ein klareres Setup, eine Stop-Regel, ein Verifier-Pfad oder ein nächstes Handlungspaket.</span>
</span>
</div>
</div>
</div>
<p class="pilot-note reveal">
<span class="copy-block" data-lang-copy="en">
Pilot status: testing HAI with the first 5-10 real workflows. One workflow,
one owner packet, one follow-up.
</span>
<span class="copy-block" data-lang-copy="de">
Pilotstatus: Ich teste HAI an den ersten 5-10 echten Workflows. Ein Workflow,
ein Owner Packet, ein Follow-up.
</span>
</p>
</div>
<aside class="output-panel reveal" aria-label="4 hour audit output">
<span class="state-label">
<span class="lang-copy" data-lang-copy="en">Visible output</span>
<span class="lang-copy" data-lang-copy="de">Sichtbarer Output</span>
</span>
<h3>
<span class="copy-block" data-lang-copy="en">What you get after the 4h audit.</span>
<span class="copy-block" data-lang-copy="de">Was nach dem 4h-Audit sichtbar ist.</span>
</h3>
<p>
<span class="copy-block" data-lang-copy="en">
A compact owner packet shaped by practical depth: Samuel has already seen
how agent workflows drift into overload, weak ownership, and false done signals.
</span>
<span class="copy-block" data-lang-copy="de">
Ein kompaktes Owner Packet aus echter Praxis: Ich kenne die Stellen, an denen
Agenten-Workflows in Overload, schwache Ownership und falsche Fertig-Signale kippen.
</span>
</p>
<ul class="output-list">
<li>
<span class="lang-copy" data-lang-copy="en">Workflow diagnosis</span>
<span class="lang-copy" data-lang-copy="de">Workflow-Diagnose</span>
</li>
<li>
<span class="lang-copy" data-lang-copy="en">3 friction points</span>
<span class="lang-copy" data-lang-copy="de">3 Reibungspunkte</span>
</li>
<li>
<span class="lang-copy" data-lang-copy="en">3 immediate changes</span>
<span class="lang-copy" data-lang-copy="de">3 Sofortänderungen</span>
</li>
<li>
<span class="lang-copy" data-lang-copy="en">Human gates</span>
<span class="lang-copy" data-lang-copy="de">Human Gates</span>
</li>
<li>
<span class="lang-copy" data-lang-copy="en">Verification rule</span>
<span class="lang-copy" data-lang-copy="de">Prüfregel</span>
</li>
<li>
<span class="lang-copy" data-lang-copy="en">Next Action Packet</span>
<span class="lang-copy" data-lang-copy="de">Nächstes Handlungspaket</span>
</li>
</ul>
<p class="trust-bridge">
<span class="copy-block" data-lang-copy="en">
The trust bridge is simple: he has already been where your problem can go.
The value is learning where your agent system breaks, who owns the decision,
and how the next step becomes checkable.
</span>
<span class="copy-block" data-lang-copy="de">
Die Trust-Brücke ist einfach: Ich war schon an vielen Stellen, an denen dein Problem hinführen kann.
Der Wert liegt darin, herauszufinden, wo dein Agentensystem bricht, wer entscheidet
und wie der nächste Schritt prüfbar wird.
</span>
</p>
<div class="fit-actions">
<a
class="button primary"
data-site-event="cta_click"
data-event-target="intake_start"
href="/intake/"
>
<span class="lang-copy" data-lang-copy="en">Start workflow intake</span>
<span class="lang-copy" data-lang-copy="de">Workflow-Intake starten</span>
</a>
<a
class="button"
data-site-event="cta_click"
data-event-target="contact_fit_call"
href="mailto:samuel@human-agent-interface.com?subject=20%20min%20HAI%20fit%20call&amp;body=Hi%20Samuel%2C%0D%0A%0D%0AI%20want%20to%20book%20a%2020%20min%20HAI%20fit%20call.%0D%0A%0D%0A1.%20What%20agent%20workflow%20is%20creating%20confusion%3F%0D%0A%0D%0A2.%20Where%20do%20I%20lose%20control%2C%20overview%2C%20or%20trust%3F%0D%0A%0D%0A3.%20What%20would%20be%20useful%20after%204%20hours%3F%0D%0A%0D%0APreferred%20time%20windows%3A"
>
<span class="lang-copy" data-lang-copy="en">Test 20 min HAI fit call</span>
<span class="lang-copy" data-lang-copy="de">20-Min-Fit-Call testen</span>
</a>
<a class="button" data-site-event="cta_click" data-event-target="hero_product" href="./product/">
<span class="lang-copy" data-lang-copy="en">See the 4h setup</span>
<span class="lang-copy" data-lang-copy="de">4h-Setup ansehen</span>
</a>
</div>
</aside>
</div>
</section>
<section class="wide-statement" aria-label="Human tool statement">
<div class="section-inner">
<p class="tool-line reveal">
<span class="copy-block" data-lang-copy="en">Humans are tool-using animals. Agents are the most powerful tool we have ever built.</span>
<span class="copy-block" data-lang-copy="de">Menschen nutzen Werkzeuge. Agents sind das mächtigste Werkzeug, das wir bisher gebaut haben.</span>
</p>
<p class="reveal">
<span class="copy-block" data-lang-copy="en">
Voice, text, drawing, terminal, IDE, browser, or background process are only
surfaces. The real interface is how the human directs, scopes, verifies, and
stays aligned with a system that can act.
</span>
<span class="copy-block" data-lang-copy="de">
Stimme, Text, Skizze, Terminal, IDE, Browser oder Hintergrundprozess sind nur
Oberflächen. Das echte Interface ist die Frage, wie der Mensch ein handelndes
System richtet, begrenzt, prüft und ausgerichtet hält.
</span>
</p>
</div>
</section>
<section class="section authority-teaser" aria-labelledby="authority-title">
<div class="section-inner authority-grid">
<div>
<p class="kicker reveal">
<span class="lang-copy" data-lang-copy="en">Why trust this work</span>
<span class="lang-copy" data-lang-copy="de">Warum mir diese Arbeit zuzutrauen ist</span>
</p>
<h2 class="reveal" id="authority-title">
<span class="copy-block" data-lang-copy="en">Samuel has already lived where agent work breaks.</span>
<span class="copy-block" data-lang-copy="de">Ich kenne die Stellen, an denen Agentenarbeit bricht.</span>
</h2>
<p class="body-copy reveal">
<span class="copy-block" data-lang-copy="en">
Samuel Fleig develops Human Agent Interface (HAI) from repeated work with terminal agents,
coding agents, harnesses, and owner-control artifacts. HAI-MCP is the open-source MCP
control-plane implementation of that method.
</span>
<span class="copy-block" data-lang-copy="de">
Ich habe die spätere Version des Problems schon gesehen: mehr Agents,
mehr Output, mehr Dashboards und weniger menschliche Ownership.
</span>
</p>
</div>
<aside class="authority-panel reveal" aria-label="Samuel trust layer">
<span>
<span class="lang-copy" data-lang-copy="en">Proof of depth</span>
<span class="lang-copy" data-lang-copy="de">Nachweis von Tiefe</span>
</span>
<p>
<span class="copy-block" data-lang-copy="en">
The artifact trail matters because it shows repeated contact with the same failure
path: Sidecar, HAI, harnesses, control surfaces, Luis handoffs, and failed
control-tower attempts turned into stricter workflow rules.
</span>
<span class="copy-block" data-lang-copy="de">
Die Artefaktspur ist wichtig, weil sie wiederholt denselben Failure-Pfad zeigt:
Sidecar, HAI, Harnesses, Kontrollflächen, Luis-Handoffs und gescheiterte
Control-Tower-Versuche wurden zu strengeren Workflow-Regeln.
</span>
</p>
<a class="button" href="./sidecar/">
<span class="lang-copy" data-lang-copy="en">See the Sidecar control layer</span>
<span class="lang-copy" data-lang-copy="de">Sidecar-Kontrollschicht ansehen</span>
</a>
<a class="button" href="./proof/">
<span class="lang-copy" data-lang-copy="en">See proof</span>
<span class="lang-copy" data-lang-copy="de">Nachweis ansehen</span>
</a>
</aside>
</div>
</section>
<section class="section conversion" id="conversion" aria-labelledby="conversion-title">
<div class="section-inner">
<p class="kicker reveal">
<span class="lang-copy" data-lang-copy="en">The product unit is a conversion</span>
<span class="lang-copy" data-lang-copy="de">Die kleinste Einheit</span>
</p>
<h2 class="reveal" id="conversion-title">
<span class="copy-block" data-lang-copy="en">From scattered agent work to one concrete packet.</span>
<span class="copy-block" data-lang-copy="de">Von verstreuter Agentenarbeit zu einem konkreten Paket.</span>
</h2>
<div class="conversion-grid">
<article class="state before reveal">
<div class="state-content">
<span class="state-label">
<span class="lang-copy" data-lang-copy="en">Before HAI</span>
<span class="lang-copy" data-lang-copy="de">Vor HAI</span>
</span>
<h3>
<span class="lang-copy" data-lang-copy="en">Messy human state</span>
<span class="lang-copy" data-lang-copy="de">Unklarer menschlicher Zustand</span>
</h3>
<ul>
<li>
<span class="lang-copy" data-lang-copy="en">An idea with no shape.</span>
<span class="lang-copy" data-lang-copy="de">Eine Idee ohne Form.</span>
</li>
<li>
<span class="lang-copy" data-lang-copy="en">A stuck project with unclear ownership.</span>
<span class="lang-copy" data-lang-copy="de">Ein festhängendes Projekt mit unklarer Ownership.</span>
</li>
<li>
<span class="lang-copy" data-lang-copy="en">Too many agent threads competing for attention.</span>
<span class="lang-copy" data-lang-copy="de">Zu viele Agenten-Threads konkurrieren um Aufmerksamkeit.</span>
</li>
<li>
<span class="lang-copy" data-lang-copy="en">No trusted next step.</span>
<span class="lang-copy" data-lang-copy="de">Kein vertrauenswürdiger nächster Schritt.</span>
</li>
</ul>
</div>
</article>
<article class="state after reveal">
<div class="state-content">
<span class="state-label">
<span class="lang-copy" data-lang-copy="en">After HAI</span>
<span class="lang-copy" data-lang-copy="de">Nach HAI</span>
</span>
<h3>
<span class="lang-copy" data-lang-copy="en">Agent-ready next action</span>
<span class="lang-copy" data-lang-copy="de">Agent-ready nächster Schritt</span>
</h3>
<ul>
<li>
<span class="lang-copy" data-lang-copy="en">The problem type is named.</span>
<span class="lang-copy" data-lang-copy="de">Der Problemtyp ist benannt.</span>
</li>
<li>
<span class="lang-copy" data-lang-copy="en">Human decisions stay with the human.</span>
<span class="lang-copy" data-lang-copy="de">Menschliche Entscheidungen bleiben beim Menschen.</span>
</li>
<li>
<span class="lang-copy" data-lang-copy="en">Agent work is bounded and verifiable.</span>
<span class="lang-copy" data-lang-copy="de">Agentenarbeit ist begrenzt und prüfbar.</span>
</li>
<li>
<span class="lang-copy" data-lang-copy="en">The next packet of work is concrete.</span>
<span class="lang-copy" data-lang-copy="de">Das nächste Arbeitspaket ist konkret.</span>
</li>
</ul>
</div>
</article>
</div>
</div>
</section>
<section class="section" aria-labelledby="category-title">
<div class="section-inner split">
<div>
<p class="kicker reveal">
<span class="lang-copy" data-lang-copy="en">The interface shift</span>
<span class="lang-copy" data-lang-copy="de">Der Interface-Wechsel</span>
</p>
<h2 class="reveal" id="category-title">
<span class="copy-block" data-lang-copy="en">GUI gave us control over screens. HAI gives us control over agency.</span>
<span class="copy-block" data-lang-copy="de">GUI gab uns Kontrolle über Screens. HAI gibt Kontrolle über Handlung.</span>
</h2>
</div>
<div class="quote-rail">
<div class="quote-tile reveal">
<span>CLI</span>
<strong>
<span class="lang-copy" data-lang-copy="en">Tell the machine what to run.</span>
<span class="lang-copy" data-lang-copy="de">Sag der Maschine, was sie ausführen soll.</span>
</strong>
</div>
<div class="quote-tile reveal">
<span>GUI</span>
<strong>
<span class="lang-copy" data-lang-copy="en">Point at what the software exposes.</span>
<span class="lang-copy" data-lang-copy="de">Zeig auf das, was die Software sichtbar macht.</span>
</strong>
</div>
<div class="quote-tile reveal">
<span>HAI</span>
<strong>
<span class="lang-copy" data-lang-copy="en">Shape what an agent should do next.</span>
<span class="lang-copy" data-lang-copy="de">Forme, was ein Agent als Nächstes tun darf.</span>
</strong>
</div>
</div>
</div>
</section>
<section class="section" aria-labelledby="method-title">
<div class="section-inner">
<p class="kicker reveal">
<span class="lang-copy" data-lang-copy="en">The minimum loop</span>
<span class="lang-copy" data-lang-copy="de">Der minimale Loop</span>
</p>
<h2 class="reveal" id="method-title">
<span class="copy-block" data-lang-copy="en">A human-owned path into agentic work.</span>
<span class="copy-block" data-lang-copy="de">Ein vom Menschen gesteuerter Weg in agentische Arbeit.</span>
</h2>
<div class="method-grid" aria-label="HAI method">
<article class="step reveal">
<span>01</span>
<h3>Intake</h3>
<p>
<span class="lang-copy" data-lang-copy="en">Capture the messy state without pretending it is already a task.</span>
<span class="lang-copy" data-lang-copy="de">Den unklaren Zustand aufnehmen, ohne so zu tun, als wäre er schon ein Task.</span>
</p>
</article>
<article class="step reveal">
<span>02</span>
<h3>
<span class="lang-copy" data-lang-copy="en">Classify</span>
<span class="lang-copy" data-lang-copy="de">Einordnen</span>
</h3>
<p>
<span class="lang-copy" data-lang-copy="en">Name what this is: decision, research, build, repair, or human-only.</span>
<span class="lang-copy" data-lang-copy="de">Benennen, was es ist: Entscheidung, Recherche, Build, Reparatur oder human-only.</span>
</p>
</article>
<article class="step reveal">
<span>03</span>
<h3>
<span class="lang-copy" data-lang-copy="en">Separate</span>
<span class="lang-copy" data-lang-copy="de">Trennen</span>
</h3>
<p>
<span class="lang-copy" data-lang-copy="en">Keep judgment, risk, and irreversible choices with the human.</span>
<span class="lang-copy" data-lang-copy="de">Urteil, Risiko und irreversible Entscheidungen beim Menschen lassen.</span>
</p>
</article>
<article class="step reveal">
<span>04</span>
<h3>Scope</h3>
<p>
<span class="lang-copy" data-lang-copy="en">Bound the agent work so it can be executed and checked.</span>
<span class="lang-copy" data-lang-copy="de">Agentenarbeit so begrenzen, dass sie ausgeführt und geprüft werden kann.</span>
</p>
</article>
<article class="step reveal">
<span>05</span>
<h3>Packet</h3>
<p>
<span class="lang-copy" data-lang-copy="en">Produce the next concrete action the agent can actually take.</span>
<span class="lang-copy" data-lang-copy="de">Die nächste konkrete Handlung erzeugen, die ein Agent wirklich tun kann.</span>
</p>
</article>
</div>
</div>
</section>
<section class="section contact" id="contact" aria-labelledby="contact-title">
<div class="section-inner contact-panel">
<div>
<p class="kicker reveal">
<span class="lang-copy" data-lang-copy="en">20 min HAI fit call</span>
<span class="lang-copy" data-lang-copy="de">Fit-Call als Test</span>
</p>
<h2 class="reveal" id="contact-title">
<span class="copy-block" data-lang-copy="en">Bring one workflow where control breaks.</span>
<span class="copy-block" data-lang-copy="de">Bring einen Workflow, an dem Kontrolle bricht.</span>
</h2>
</div>
<div class="contact-note reveal">
<p>
<span class="copy-block" data-lang-copy="en">
Show me one agent workflow that currently creates confusion. Leave with
the next concrete packet of work: what this is, what an agent should do,
what you must decide yourself, and what happens next.
</span>
<span class="copy-block" data-lang-copy="de">
Zeig mir einen Agenten-Workflow, der gerade Verwirrung erzeugt. Ziel ist kein Verkaufstrick,
sondern ein Test: Wird daraus ein konkretes Arbeitspaket, eine klare menschliche Entscheidung
und ein prüfbarer nächster Schritt?
</span>
</p>
<p style="margin-top: 24px;">
<a
class="button primary"
data-site-event="cta_click"
data-event-target="contact_fit_call"
href="mailto:samuel@human-agent-interface.com?subject=20%20min%20HAI%20fit%20call&amp;body=Hi%20Samuel%2C%0D%0A%0D%0AI%20want%20to%20book%20a%2020%20min%20HAI%20fit%20call.%0D%0A%0D%0A1.%20What%20agent%20workflow%20is%20creating%20confusion%3F%0D%0A%0D%0A2.%20Where%20do%20I%20lose%20control%2C%20overview%2C%20or%20trust%3F%0D%0A%0D%0A3.%20What%20would%20be%20useful%20after%204%20hours%3F%0D%0A%0D%0APreferred%20time%20windows%3A"
>
<span class="lang-copy" data-lang-copy="en">Test 20 min HAI fit call</span>
<span class="lang-copy" data-lang-copy="de">20-Min-Fit-Call testen</span>
</a>
</p>
</div>
</div>
</section>
</main>
<footer>
<div class="section-inner">
<span>Human Agent Interface (HAI) by Samuel Fleig</span>
<span>
<span class="lang-copy" data-lang-copy="en">CLI -> TUI -> GUI -> HAI</span>
<span class="lang-copy" data-lang-copy="de">CLI -> TUI -> GUI -> HAI: Kontrolle über Agentenarbeit</span>
</span>
</div>
</footer>
<script>
document.documentElement.classList.add("js");
const HERO_EXPERIMENT_ID = "homepage-hero-2026-05-23";
const HERO_VARIANTS = ["A_control", "B_offer_first", "C_proof_first"];
function isHeroVariant(value) {
return HERO_VARIANTS.includes(value);
}
function readCookie(name) {
const prefix = `${name}=`;
return document.cookie
.split(";")
.map((part) => part.trim())
.find((part) => part.startsWith(prefix))
?.slice(prefix.length) || "";
}
function writeHeroVariantCookie(variant) {
document.cookie = `haiHeroVariant=${variant}; Max-Age=2592000; Path=/; SameSite=Lax`;
}
function chooseHeroVariant() {
const params = new URLSearchParams(window.location.search);
const previewVariant = params.get("hero_variant");
if (isHeroVariant(previewVariant)) {
document.documentElement.dataset.heroVariant = previewVariant;
document.documentElement.dataset.heroExperiment = HERO_EXPERIMENT_ID;
return { variant: previewVariant, preview: true };
}
let variant = document.documentElement.dataset.heroVariant;
if (!isHeroVariant(variant)) {
const cookieVariant = readCookie("haiHeroVariant");
variant = isHeroVariant(cookieVariant)
? cookieVariant
: HERO_VARIANTS[Math.floor(Math.random() * HERO_VARIANTS.length)];
writeHeroVariantCookie(variant);
}
document.documentElement.dataset.heroVariant = variant;
document.documentElement.dataset.heroExperiment = HERO_EXPERIMENT_ID;
return { variant, preview: false };
}
const heroExperiment = chooseHeroVariant();
const storedLang = (() => {
try {
return localStorage.getItem("haiLang");
} catch {
return null;
}
})();
const browserLang = (navigator.languages || [navigator.language || "en"]).some((lang) => lang.toLowerCase().startsWith("de")) ? "de" : "en";
function setLanguage(lang, persist = false) {
const normalized = lang === "de" ? "de" : "en";
document.documentElement.classList.toggle("lang-de", normalized === "de");
document.documentElement.classList.toggle("lang-en", normalized === "en");
document.documentElement.lang = normalized;
document.querySelectorAll("[data-lang-toggle]").forEach((button) => {
button.setAttribute("aria-pressed", String(button.dataset.langToggle === normalized));
});
if (persist) {
try {
localStorage.setItem("haiLang", normalized);
} catch {
/* Language preference is optional. */
}
}
}
document.querySelectorAll("[data-lang-toggle]").forEach((button) => {
button.addEventListener("click", () => setLanguage(button.dataset.langToggle, true));
});
setLanguage(storedLang || browserLang);
function viewportClass() {
if (window.matchMedia("(max-width: 620px)").matches) return "mobile";
if (window.matchMedia("(max-width: 900px)").matches) return "tablet";
return "desktop";
}
function sendSiteEvent(event, target = "") {
if (heroExperiment.preview) return;
const payload = JSON.stringify({
experiment_id: HERO_EXPERIMENT_ID,
variant: heroExperiment.variant,
event,
target,
path: window.location.pathname || "/",
language: document.documentElement.lang || "en",
viewport_class: viewportClass(),
});
if (navigator.sendBeacon) {
const body = new Blob([payload], { type: "application/json" });
if (navigator.sendBeacon("/api/site-event", body)) return;
}
fetch("/api/site-event", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: payload,
keepalive: true,
}).catch(() => {
/* Analytics must never block navigation. */
});
}
sendSiteEvent("hero_impression");
document.querySelectorAll("[data-site-event]").forEach((element) => {
element.addEventListener("click", () => {
sendSiteEvent(element.dataset.siteEvent, element.dataset.eventTarget || "");
});
});
const canvas = document.getElementById("agentField");
const ctx = canvas.getContext("2d");
const media = window.matchMedia("(prefers-reduced-motion: reduce)");
let width = 0;
let height = 0;
let ratio = 1;
let particles = [];
let pointer = { x: 0.72, y: 0.38 };
function resize() {
ratio = Math.min(window.devicePixelRatio || 1, 2);
width = canvas.clientWidth;
height = canvas.clientHeight;
canvas.width = Math.floor(width * ratio);
canvas.height = Math.floor(height * ratio);
ctx.setTransform(ratio, 0, 0, ratio, 0, 0);
const count = Math.max(38, Math.min(86, Math.floor(width / 18)));
particles = Array.from({ length: count }, (_, index) => ({
x: (index * 193) % Math.max(width, 1),
y: (index * 317) % Math.max(height, 1),
vx: ((index % 7) - 3) * 0.08,
vy: (((index * 3) % 9) - 4) * 0.06,
r: 1.4 + (index % 4) * 0.65
}));
}
function drawGrid(time) {
ctx.clearRect(0, 0, width, height);
ctx.globalAlpha = 1;
ctx.fillStyle = "#090a08";
ctx.fillRect(0, 0, width, height);
const spacing = Math.max(54, Math.min(92, width / 14));
ctx.lineWidth = 1;
for (let x = -spacing; x < width + spacing; x += spacing) {
const wave = Math.sin(time * 0.0004 + x * 0.01) * 16;
ctx.strokeStyle = "rgba(247, 241, 223, 0.055)";
ctx.beginPath();
ctx.moveTo(x + wave, 0);
ctx.lineTo(x - wave * 0.4, height);
ctx.stroke();
}
for (let y = -spacing; y < height + spacing; y += spacing) {
ctx.strokeStyle = "rgba(247, 241, 223, 0.045)";
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(width, y + Math.sin(time * 0.0005 + y * 0.01) * 18);
ctx.stroke();
}
}
function drawParticles(time) {
const focusX = pointer.x * width;
const focusY = pointer.y * height;
for (const point of particles) {
point.x += media.matches ? 0 : point.vx;
point.y += media.matches ? 0 : point.vy;
if (point.x < -20) point.x = width + 20;
if (point.x > width + 20) point.x = -20;
if (point.y < -20) point.y = height + 20;
if (point.y > height + 20) point.y = -20;
const dx = point.x - focusX;
const dy = point.y - focusY;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 190) {
ctx.strokeStyle = `rgba(167, 255, 79, ${0.2 * (1 - distance / 190)})`;
ctx.beginPath();
ctx.moveTo(focusX, focusY);
ctx.lineTo(point.x, point.y);
ctx.stroke();
}
ctx.fillStyle = distance < 190 ? "rgba(167, 255, 79, 0.86)" : "rgba(247, 241, 223, 0.28)";
ctx.beginPath();
ctx.arc(point.x, point.y, point.r, 0, Math.PI * 2);
ctx.fill();
}
const pulse = 12 + Math.sin(time * 0.003) * 4;
ctx.strokeStyle = "rgba(167, 255, 79, 0.64)";
ctx.lineWidth = 1;
ctx.beginPath();
ctx.arc(focusX, focusY, pulse, 0, Math.PI * 2);
ctx.stroke();
ctx.fillStyle = "rgba(167, 255, 79, 0.18)";
ctx.beginPath();
ctx.arc(focusX, focusY, pulse * 2.6, 0, Math.PI * 2);
ctx.fill();
}
function frame(time) {
drawGrid(time);
drawParticles(time);
if (!media.matches) requestAnimationFrame(frame);
}
window.addEventListener("resize", resize);
window.addEventListener("pointermove", (event) => {
pointer = {
x: event.clientX / Math.max(window.innerWidth, 1),
y: event.clientY / Math.max(window.innerHeight, 1)
};
});
const observer = new IntersectionObserver((entries) => {
for (const entry of entries) {
if (entry.isIntersecting) entry.target.classList.add("is-visible");
}
}, { threshold: 0.14 });
document.querySelectorAll(".reveal").forEach((element) => observer.observe(element));
resize();
requestAnimationFrame(frame);
</script>
</body>
</html>