124 lines
5.3 KiB
HTML
124 lines
5.3 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8"/>
|
|
<title>LazyBoy hero</title>
|
|
<style>
|
|
@font-face {
|
|
font-family: Huninn;
|
|
font-weight: 400;
|
|
src: url("../apps/web/node_modules/@fontsource/huninn/files/huninn-latin-400-normal.woff2") format("woff2");
|
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F;
|
|
}
|
|
@font-face {
|
|
font-family: Huninn;
|
|
font-weight: 400;
|
|
src: url("../apps/web/node_modules/@fontsource/huninn/files/huninn-latin-ext-400-normal.woff2") format("woff2");
|
|
unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1EFF;
|
|
}
|
|
@font-face {
|
|
font-family: Huninn;
|
|
font-weight: 400;
|
|
src: url("../apps/web/node_modules/@fontsource/huninn/files/huninn-chinese-traditional-400-normal.woff2") format("woff2");
|
|
unicode-range: U+4E00-9FFF, U+3400-4DBF, U+F900-FAFF, U+3000-303F, U+FF00-FFEF;
|
|
}
|
|
* { box-sizing: border-box; }
|
|
html, body {
|
|
margin: 0;
|
|
width: 1280px;
|
|
height: 760px;
|
|
overflow: hidden;
|
|
background: #f3f3f5;
|
|
color: #161618;
|
|
font-family: Huninn, "jf open 粉圓", "PingFang TC", sans-serif;
|
|
}
|
|
.page { width: 1280px; height: 760px; padding: 30px 48px 0; }
|
|
.top { display: flex; align-items: center; justify-content: space-between; height: 36px; }
|
|
.brand { display: flex; align-items: center; gap: 10px; font-size: 20px; letter-spacing: .02em; }
|
|
.brand svg { width: 26px; height: 26px; }
|
|
.pill {
|
|
display: inline-flex; align-items: center; gap: 8px; height: 28px; padding: 0 12px;
|
|
border: 1px solid #e4e4e8; border-radius: 999px; background: #fff; color: #5c5c64; font-size: 12px;
|
|
}
|
|
.pill b { color: #0f766e; font-weight: 400; }
|
|
.copy { text-align: center; margin: 20px auto 18px; max-width: 820px; }
|
|
h1 { margin: 0; font-size: 40px; font-weight: 400; letter-spacing: .01em; line-height: 1.15; }
|
|
.lead { margin: 10px 0 0; color: #6b6b73; font-size: 15px; line-height: 1.55; }
|
|
.window {
|
|
width: 1184px; height: 554px; margin: 0 auto;
|
|
border-radius: 16px 16px 0 0; overflow: hidden; background: #0d0d0e;
|
|
box-shadow: 0 24px 70px rgba(16, 16, 20, .28), 0 0 0 1px rgba(0,0,0,.08);
|
|
display: grid; grid-template-rows: 34px 1fr;
|
|
}
|
|
.chrome {
|
|
display: flex; align-items: center; gap: 7px; padding: 0 14px;
|
|
background: #161618; border-bottom: 1px solid #202023;
|
|
}
|
|
.dot { width: 10px; height: 10px; border-radius: 50%; }
|
|
.dot.r { background: #ff5f57; }
|
|
.dot.y { background: #febc2e; }
|
|
.dot.g { background: #28c840; }
|
|
/* Real pixels: docs/hero/*.png comes from scripts/capture-hero.mjs. */
|
|
/* 1184x520 matches the capture ratio (1480x650), so nothing is cropped. */
|
|
.shot { position: relative; width: 1184px; height: 520px; overflow: hidden; }
|
|
.shot img { position: absolute; display: block; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="page">
|
|
<div class="top">
|
|
<div class="brand">
|
|
<svg viewBox="0 0 64 64" aria-hidden="true">
|
|
<path fill="#3ec5a8" d="M33 5c11.5 1 24 11 23 26-1 14-11 27-25 28S6 47 7 31 21 4 33 5z"/>
|
|
<ellipse cx="25.5" cy="29" rx="4.2" ry="5" fill="#1b1b22"/>
|
|
<ellipse cx="40.5" cy="29" rx="4.2" ry="5" fill="#1b1b22"/>
|
|
<circle cx="26.8" cy="27.2" r="1.3" fill="#f3f3f6"/>
|
|
<circle cx="41.8" cy="27.2" r="1.3" fill="#f3f3f6"/>
|
|
</svg>
|
|
LazyBoy
|
|
</div>
|
|
<div class="pill"><b>Self-hosted</b> a Linux desktop per agent</div>
|
|
</div>
|
|
<div class="copy">
|
|
<h1>Give an agent a real computer</h1>
|
|
<p class="lead">
|
|
Assign work by text, voice, or a quick demo, then watch its own Linux desktop do it.<br/>
|
|
Chats, memory, and desktops stay on your host. You choose the model.
|
|
</p>
|
|
</div>
|
|
<div class="window">
|
|
<div class="chrome"><i class="dot r"></i><i class="dot y"></i><i class="dot g"></i></div>
|
|
<div class="shot"></div>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
// Every layer is a real capture from scripts/capture-hero.mjs, so the banner
|
|
// never shows an invented UI. The group view is two layers on purpose:
|
|
// room.png is captured with `--hide .side-card`, which blanks the desktop
|
|
// panel (an agent's browser holds whatever its owner left open), and
|
|
// desktop.png drops a neutral one back in at the anchor the same capture
|
|
// prints. Captures are 2x shots of a 1480px viewport, so a capture-space
|
|
// number becomes hero-space by multiplying by 1184 / 1480 = 0.8.
|
|
const layers = {
|
|
room: [
|
|
{ src: './hero/room.png', x: 0, y: 0, w: 1184, h: 520 },
|
|
{ src: './hero/desktop.png', x: 832, y: 0, w: 352, h: 520 },
|
|
],
|
|
agent: [{ src: './hero/agent.png', x: 0, y: 0, w: 1184, h: 520 }],
|
|
};
|
|
const shot = new URLSearchParams(location.search).get('shot') || 'room';
|
|
const host = document.querySelector('.shot');
|
|
(layers[shot] || layers.room).forEach((layer) => {
|
|
const img = document.createElement('img');
|
|
img.src = layer.src;
|
|
img.alt = 'LazyBoy group chat routing one message to an agent on its live desktop';
|
|
img.style.left = `${layer.x}px`;
|
|
img.style.top = `${layer.y}px`;
|
|
img.style.width = `${layer.w}px`;
|
|
img.style.height = `${layer.h}px`;
|
|
host.appendChild(img);
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|