2026-05-31 23:58:26 +09:00
<!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< meta name = "description" content = "Odysseus — a self-hosted AI workspace: chat, agents, tools, model serving, email, research, and more. Your models, your hardware, your data." >
< title > Odysseus — A Self-Hosted AI Workspace< / title >
< link rel = "icon" type = "image/svg+xml" href = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M16 4L16 22L6 22Z' fill='%23e06c75'/%3E%3Cpath d='M16 8L16 22L24 22Z' fill='%23e06c75' opacity='0.6'/%3E%3Cpath d='M4 24Q10 20 16 24Q22 28 28 24' stroke='%23e06c75' stroke-width='2.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E" >
< style >
:root {
/* Odysseus default theme — exact app tokens */
--bg: #282c34;
--bg2: #1e2228; /* app code/hl background */
--panel: #111; /* app panel surface */
--panel2: #1e2228;
--fg: #9cdef2; /* signature cyan text */
--heading: #9cdef2;
--muted: #6b8a94; /* app subheader */
--border: #355a66; /* teal border */
--accent: #e06c75; /* app accent (the send-button coral) */
--accent2: #f0989e; /* lighter coral for gradients */
--green: #50fa7b;
--gold: #f0ad4e; /* app --warn */
--red: #e06c75;
--radius: 8px;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; scroll-snap-type: y mandatory; scroll-padding-top: 60px; }
/* Each section is a full-viewport "page" with its content centered, so only
one shows at a time and the snap is obvious. */
.hero, section {
scroll-snap-align: start; min-height: 100vh;
display: flex; flex-direction: column; justify-content: center;
}
/* Alternate the page backgrounds: slate (the body) ↔ black, to make each
page boundary obvious. */
section:nth-of-type(odd) { background: #111111; }
section:nth-of-type(even) { background: var(--bg); }
/* Domino reveal — each section fades/slides up as it scrolls into view. */
.hero, section { opacity: 0; transform: translateY(24px); transition: opacity .6s cubic-bezier(.2,.7,.2,1), transform .6s cubic-bezier(.2,.7,.2,1); }
.hero.in, section.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
html { scroll-snap-type: none; }
.hero, section { opacity: 1 !important; transform: none !important; transition: none; }
}
/* Capabilities cards cascade in like the app's domino expand. */
#features .feature { opacity: 0; transform: translateY(16px); }
#features.in .feature { animation: domino-in .5s cubic-bezier(.2,.7,.2,1) forwards; }
#features.in .feature:nth-child(1) { animation-delay: .04s; }
#features.in .feature:nth-child(2) { animation-delay: .09s; }
#features.in .feature:nth-child(3) { animation-delay: .14s; }
#features.in .feature:nth-child(4) { animation-delay: .19s; }
#features.in .feature:nth-child(5) { animation-delay: .24s; }
#features.in .feature:nth-child(6) { animation-delay: .29s; }
#features.in .feature:nth-child(7) { animation-delay: .34s; }
#features.in .feature:nth-child(8) { animation-delay: .39s; }
#features.in .feature:nth-child(9) { animation-delay: .44s; }
@keyframes domino-in { to { opacity: 1; transform: none; } }
body {
margin: 0;
background:
radial-gradient(1100px 520px at 82% -10%, rgba(224,108,117,0.12), transparent 60%),
radial-gradient(900px 520px at 0% 0%, rgba(53,90,102,0.30), transparent 55%),
var(--bg);
color: var(--fg);
font-family: 'Fira Code', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
line-height: 1.6;
-webkit-font-smoothing: antialiased;
}
a { color: var(--accent); text-decoration: none; }
.wrap { max-width: 1080px; margin: 0 auto; padding: 0 22px; }
/* Nav */
nav {
position: sticky; top: 0; z-index: 50;
backdrop-filter: blur(10px);
background: rgba(17,17,17,0.88);
border-bottom: 1px solid #9cdef2;
}
nav .wrap { display: flex; align-items: center; justify-content: space-between; height: 60px; }
.brand { display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: 17px; letter-spacing: 0.2px; color: var(--heading); }
.brand .boat { color: var(--accent); flex-shrink: 0; }
.nav-links { display: flex; align-items: center; gap: 22px; }
.nav-links a { color: var(--muted); font-size: 14px; font-weight: 500; }
.nav-links a:hover { color: var(--fg); }
.btn {
display: inline-flex; align-items: center; gap: 8px;
padding: 9px 16px; border-radius: 10px; font-weight: 600; font-size: 14px;
border: 1px solid var(--border); color: var(--fg); background: var(--panel);
transition: transform .12s ease, border-color .12s ease, background .12s ease;
}
.btn:hover { transform: translateY(-1px); border-color: var(--accent); }
.btn.primary {
background: linear-gradient(135deg, var(--accent), var(--accent2));
color: #fff; border: none;
}
.btn.primary:hover { filter: brightness(1.07); }
2026-06-01 15:57:01 +04:00
.nav-links-hamburger {
display: none;
position: relative;
}
.hamburger-btn {
display: flex;
align-items: center;
justify-content: center;
width: 42px;
height: 42px;
border: 1px solid var(--border);
border-radius: 8px;
background: var(--panel);
color: var(--fg);
cursor: pointer;
}
.hamburger-btn:hover {
border-color: var(--accent);
}
.hamburger-menu {
position: absolute;
top: calc(100% + 10px);
right: 0;
min-width: 220px;
display: none;
flex-direction: column;
padding: 12px;
background: rgba(17,17,17,0.98);
border: 1px solid var(--border);
border-radius: var(--radius);
backdrop-filter: blur(10px);
box-shadow: 0 12px 40px rgba(0,0,0,0.4);
}
.hamburger-menu a {
color: var(--muted);
padding: 8px 10px;
border-radius: 6px;
}
.hamburger-menu a:hover {
color: var(--fg);
}
.nav-links-hamburger.open .hamburger-menu {
display: flex;
}
2026-05-31 23:58:26 +09:00
/* Hero */
.hero { padding: 86px 0 40px; text-align: center; }
.badge {
display: inline-flex; align-items: center; gap: 7px;
font-size: 12.5px; color: var(--muted); border: 1px solid var(--border);
background: var(--panel); padding: 5px 12px; border-radius: 999px; margin-bottom: 22px;
}
.badge .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--green); box-shadow: 0 0 8px var(--green); }
.hero-logo { display: flex; align-items: center; justify-content: center; gap: 14px; color: var(--accent); margin-bottom: 4px; }
.hero-logo svg { filter: drop-shadow(0 4px 18px rgba(224,108,117,0.35)); }
.hero-logo .wordmark { font-size: clamp(30px, 6vw, 44px); font-weight: 700; color: var(--heading); letter-spacing: -0.01em; line-height: 1; }
.hero h1 {
font-size: clamp(32px, 5.4vw, 52px); line-height: 1.12; margin: 0 0 18px;
letter-spacing: -0.01em; font-weight: 700; color: var(--heading);
}
.hero h1 .grad {
background: linear-gradient(120deg, var(--accent), var(--accent2));
-webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
}
.hero .slogan { font-style: italic; color: var(--accent); font-size: 12px; margin: 0 0 24px; letter-spacing: 0.3px; opacity: 0.9; }
.hero p.lede { font-size: clamp(16px, 2.4vw, 20px); color: var(--muted); max-width: 680px; margin: 0 auto 30px; }
.hero-cta { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
/* terminal origin card */
.term-intro { color: var(--fg); font-size: clamp(13px, 1.8vw, 15px); margin: 34px auto 0; max-width: 560px; }
.term {
max-width: 620px; margin: 12px auto 0; text-align: left;
background: var(--bg2); border: 1px solid var(--border); border-radius: var(--radius);
overflow: hidden; box-shadow: 0 24px 60px rgba(0,0,0,0.4);
}
.term-bar { display: flex; align-items: center; justify-content: space-between; padding: 5px 6px 5px 12px; border-bottom: 1px solid var(--border); background: #20242c; }
.term-bar .ttl { color: var(--muted); font-size: 12px; font-family: 'Fira Code', ui-monospace, monospace; }
.term-bar .winbtns { display: flex; gap: 1px; }
.term-bar .winbtns span { cursor: pointer; }
.term { transition: opacity .18s ease, transform .18s ease; }
/* Minimized = a rounded "pill", like the app's tab-down dock chip. */
.term.term-min { max-width: max-content; border-radius: 999px; box-shadow: 0 6px 22px rgba(0,0,0,0.4); }
.term.term-min .term-bar { border-bottom: none; border-radius: 999px; padding: 7px 10px 7px 16px; gap: 12px; background: var(--panel); }
.term.term-min pre { display: none; }
.term.term-closed { opacity: 0; transform: scale(0.96); pointer-events: none; height: 0; margin: 0 auto; border: 0; overflow: hidden; }
.term-reopen {
display: none; margin: 14px auto 0; font-family: 'Fira Code', monospace; font-size: 12px;
color: var(--muted); background: none; border: 1px dashed var(--border); border-radius: 6px;
padding: 5px 12px; cursor: pointer;
}
.term-reopen:hover { color: var(--accent); border-color: var(--accent); }
.term-reopen.show { display: inline-block; }
.term-bar .winbtns span {
width: 28px; height: 20px; display: inline-flex; align-items: center; justify-content: center;
border-radius: 4px; color: var(--muted); font-size: 12px; line-height: 1;
}
.term-bar .winbtns span:hover { background: rgba(156,222,242,0.12); color: var(--fg); }
.term-bar .winbtns span.x:hover { background: #c0392b; color: #fff; }
.term pre {
margin: 0; padding: 18px 16px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 13.5px; color: var(--fg); line-height: 1.7; white-space: pre-wrap;
}
.term .cs { color: var(--green); } .term .cm { color: #828997; }
.term-cursor { display: inline-block; color: var(--fg); font-weight: 400; animation: term-blink 1.05s steps(1) infinite; }
@keyframes term-blink { 50% { opacity: 0; } }
/* Sections */
section { padding: 60px 0; }
.eyebrow { color: var(--accent); font-weight: 700; font-size: 13px; letter-spacing: 0.12em; text-transform: uppercase; }
h2.h { font-size: clamp(24px, 3.6vw, 32px); margin: 8px 0 12px; letter-spacing: -0.01em; color: var(--heading); font-weight: 700; }
.sub { color: var(--muted); max-width: 620px; }
.center { text-align: center; }
.center .sub { margin: 0 auto; }
/* Testimonial gag — single featured testimonial, click/swipe to cycle (all sizes) */
.tcarousel-wrap { position: relative; max-width: 820px; margin: 36px auto 0; }
.tarrow {
position: absolute; top: 50%; transform: translateY(-50%); z-index: 4;
width: 38px; height: 38px; border-radius: 50%;
background: rgba(17,17,17,0.85); border: 1px solid var(--border); color: var(--fg);
font-size: 20px; line-height: 1; cursor: pointer;
display: flex; align-items: center; justify-content: center;
transition: border-color .12s ease, color .12s ease;
}
.tarrow:hover { border-color: var(--accent); color: var(--accent); }
.tarrow.prev { left: 0; }
.tarrow.next { right: 0; }
.tgrid {
display: block; position: relative; overflow: hidden; cursor: pointer;
margin: 0 auto; max-width: 740px;
}
.tgrid .tcard {
display: none;
flex-direction: row-reverse; align-items: center; gap: 24px; text-align: left;
background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius);
padding: 28px;
}
.tgrid .tcard.active { display: flex; animation: tslide .25s ease both; }
.tgrid .tcard.active.shake { animation: tshake .5s ease-in-out 2 both; }
.tcard .av {
width: 84px; height: 84px; border-radius: 50%; overflow: hidden;
border: 1px solid var(--border); background: var(--panel2); flex: 0 0 auto;
}
.tcard .av img, .tcard .av svg { width: 100%; height: 100%; object-fit: cover; display: block; }
.tcard .tmeta { flex: 1 1 auto; }
.tcard .q { font-size: 18px; color: var(--fg); margin: 0 0 12px; }
.tcard .stars { font-size: 15px; letter-spacing: 3px; margin: 0 0 8px; color: var(--gold); }
.tcard .stars.zero { color: var(--muted); opacity: 0.5; }
.tcard .nm { font-weight: 700; font-size: 14.5px; }
.tcard .rl { color: var(--muted); font-size: 12.5px; }
.tcard.cyclops { border-color: rgba(255,90,90,0.45); background: linear-gradient(180deg, rgba(255,80,80,0.06), var(--panel)); }
.tcard.cyclops .q { color: #ff8a8a; font-weight: 700; letter-spacing: 0.4px; word-break: break-word; }
.tnav { display: block; text-align: center; margin-top: 18px; }
.tdot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; background: #39414d; margin: 0 4px; cursor: pointer; }
.tdot.on { background: var(--accent); }
.thint { font-size: 12px; color: var(--muted); margin-top: 8px; }
@keyframes tshake {
0%,100% { transform: translateX(0) rotate(0); }
10% { transform: translateX(-9px) rotate(-1.5deg); }
20% { transform: translateX(9px) rotate(1.5deg); }
35% { transform: translateX(-7px) rotate(-1deg); }
50% { transform: translateX(7px) rotate(1deg); }
65% { transform: translateX(-5px); } 80% { transform: translateX(4px); } 92% { transform: translateX(-2px); }
}
@keyframes tslide { from { opacity: 0; transform: translateX(24px); } to { opacity: 1; transform: none; } }
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-top: 36px; }
.feature {
background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius);
padding: 22px; transition: transform .14s ease, border-color .14s ease;
}
.feature:hover { transform: translateY(-3px); border-color: var(--accent); }
.feature .ico {
width: 40px; height: 40px; border-radius: 10px; display: inline-flex; align-items: center; justify-content: center;
background: linear-gradient(135deg, rgba(224,108,117,0.18), rgba(53,90,102,0.28));
border: 1px solid var(--border); color: var(--accent); margin-bottom: 14px;
}
.feature h3 { margin: 0 0 6px; font-size: 16.5px; }
.feature p { margin: 0; color: var(--muted); font-size: 14px; }
/* Screenshot strip */
.shotrow { display: grid; grid-template-columns: 1.4fr 1fr 1fr; gap: 16px; margin-top: 8px; }
.shot {
border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden;
background: linear-gradient(180deg, var(--panel), var(--panel2));
aspect-ratio: 16/10; display: flex; align-items: center; justify-content: center;
color: var(--muted); font-size: 13px; position: relative;
}
.shot .ph { display: flex; flex-direction: column; align-items: center; gap: 8px; opacity: 0.7; }
.shot .frame-dots { position: absolute; top: 10px; left: 12px; display: flex; gap: 5px; }
.shot .frame-dots i { width: 8px; height: 8px; border-radius: 50%; background: #39414d; display: inline-block; }
/* Previews — expanding hover carousel that plays a video on hover */
.previews { display: flex; align-items: center; gap: 12px; height: 480px; max-width: 1000px; margin: 36px auto 0; }
.preview-panel {
position: relative; flex: 1 1 0; min-width: 0; height: 360px; overflow: hidden;
border: 1px solid var(--border); border-radius: var(--radius); cursor: pointer;
background: linear-gradient(180deg, var(--panel), var(--panel2));
transition: flex-grow .5s cubic-bezier(.2,.7,.2,1), height .5s cubic-bezier(.2,.7,.2,1), border-color .25s ease;
}
.previews:hover .preview-panel { flex-grow: 0.55; height: 300px; }
.preview-panel:hover, .preview-panel:focus-visible { flex-grow: 3.4 !important; height: 480px !important; border-color: var(--accent); }
.preview-panel .ph {
position: absolute; inset: 0; display: flex; flex-direction: column;
align-items: center; justify-content: center; gap: 10px;
color: var(--muted); font-size: 12.5px; opacity: 0.7; text-align: center; padding: 8px;
}
.preview-panel video {
position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
z-index: 1; opacity: 0; transition: opacity .3s ease; background: transparent;
}
.preview-panel.has-video video { opacity: 1; }
.preview-panel .label {
position: absolute; z-index: 2; left: 0; right: 0; bottom: 0; padding: 14px 16px;
background: linear-gradient(0deg, rgba(0,0,0,0.8), transparent);
color: var(--heading); font-weight: 700; font-size: 14px;
display: flex; align-items: center; gap: 8px; white-space: nowrap;
}
.preview-panel .label .ico { color: var(--accent); flex-shrink: 0; }
@media (max-width: 760px) {
.previews { flex-direction: column; height: auto; }
.preview-panel { height: 200px; flex: none; }
.previews:hover .preview-panel, .preview-panel:hover { flex: none !important; }
}
/* Get started */
.start {
background: linear-gradient(180deg, var(--panel), var(--bg2));
border: 1px solid var(--border); border-radius: 18px; padding: 40px; text-align: center;
}
.codeblock {
display: inline-flex; align-items: center; gap: 14px; margin: 18px auto 8px;
background: var(--bg2); border: 1px solid var(--border); border-radius: 10px;
padding: 12px 16px; font-family: ui-monospace, monospace; font-size: 14px; color: var(--fg);
}
.codeblock .prompt { color: var(--accent); }
.pill-row { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-top: 18px; }
.pill { font-size: 12.5px; color: var(--muted); border: 1px solid var(--border); border-radius: 999px; padding: 5px 12px; background: var(--panel); }
2026-06-01 10:51:55 +09:00
footer { border-top: 1px solid var(--border); padding: 30px 0; color: var(--muted); font-size: 13px; scroll-snap-align: end; }
2026-05-31 23:58:26 +09:00
footer .wrap { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 12px; }
@media (max-width: 820px) {
.grid { grid-template-columns: repeat(2, 1fr); }
.shotrow { grid-template-columns: 1fr; }
2026-06-01 15:57:01 +04:00
.nav-links { display: none; }
.nav-links-hamburger { display: block; }
2026-05-31 23:58:26 +09:00
}
@media (max-width: 520px) {
.grid { grid-template-columns: 1fr; }
.tgrid .tcard { padding: 20px; gap: 16px; }
.tcard .av { width: 64px; height: 64px; }
.tcard .q { font-size: 15px; }
}
< / style >
< / head >
< body >
< nav >
< div class = "wrap" >
< div class = "brand" >
< svg class = "boat" viewBox = "0 0 32 32" width = "24" height = "24" aria-hidden = "true" > < path d = "M16 4L16 22L6 22Z" fill = "currentColor" / > < path d = "M16 8L16 22L24 22Z" fill = "currentColor" opacity = "0.6" / > < path d = "M4 24Q10 20 16 24Q22 28 28 24" stroke = "currentColor" stroke-width = "2.5" fill = "none" stroke-linecap = "round" / > < / svg >
Odysseus
< / div >
< div class = "nav-links" >
< a href = "#features" > Features< / a >
< a href = "#testimonials" > Testimonials< / a >
< a href = "#how" > How it started< / a >
< a href = "#start" > Get started< / a >
2026-06-01 10:43:35 +09:00
< a class = "btn" href = "https://github.com/pewdiepie-archdaemon/odysseus" target = "_blank" >
2026-05-31 23:58:26 +09:00
< svg width = "16" height = "16" viewBox = "0 0 24 24" fill = "currentColor" > < path d = "M12 .5C5.7.5.5 5.7.5 12c0 5.1 3.3 9.4 7.9 10.9.6.1.8-.2.8-.6v-2c-3.2.7-3.9-1.5-3.9-1.5-.5-1.3-1.3-1.7-1.3-1.7-1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1 1.8 2.7 1.3 3.4 1 .1-.8.4-1.3.7-1.6-2.6-.3-5.3-1.3-5.3-5.7 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.5.1-3.1 0 0 1-.3 3.3 1.2a11.5 11.5 0 0 1 6 0C17.3 4.7 18.3 5 18.3 5c.6 1.6.2 2.8.1 3.1.8.8 1.2 1.8 1.2 3.1 0 4.4-2.7 5.4-5.3 5.7.4.4.8 1.1.8 2.2v3.3c0 .4.2.7.8.6 4.6-1.5 7.9-5.8 7.9-10.9C23.5 5.7 18.3.5 12 .5z" / > < / svg >
GitHub
< / a >
< / div >
2026-06-01 15:57:01 +04:00
< div class = "nav-links-hamburger" >
< button class = "hamburger-btn" aria-label = "Open menu" >
< svg width = "22" height = "22" viewBox = "0 0 24 24" fill = "currentColor" >
< path d = "M3.5,7 C3.22385763,7 3,6.77614237 3,6.5 C3,6.22385763 3.22385763,6 3.5,6 L20.5,6 C20.7761424,6 21,6.22385763 21,6.5 C21,6.77614237 20.7761424,7 20.5,7 L3.5,7 Z M3.5,12 C3.22385763,12 3,11.7761424 3,11.5 C3,11.2238576 3.22385763,11 3.5,11 L20.5,11 C20.7761424,11 21,11.2238576 21,11.5 C21,11.7761424 20.7761424,12 20.5,12 L3.5,12 Z M3.5,17 C3.22385763,17 3,16.7761424 3,16.5 C3,16.2238576 3.22385763,16 3.5,16 L20.5,16 C20.7761424,16 21,16.2238576 21,16.5 C21,16.7761424 20.7761424,17 20.5,17 L3.5,17 Z" / >
< / svg >
< / button >
< div class = "hamburger-menu" >
< a href = "#features" > Features< / a >
< a href = "#testimonials" > Testimonials< / a >
< a href = "#how" > How it started< / a >
< a href = "#start" > Get started< / a >
< a class = "btn" href = "https://github.com/pewdiepie-archdaemon/odysseus" target = "_blank" >
< svg width = "16" height = "16" viewBox = "0 0 24 24" fill = "currentColor" >
< path d = "M12 .5C5.7.5.5 5.7.5 12c0 5.1 3.3 9.4 7.9 10.9.6.1.8-.2.8-.6v-2c-3.2.7-3.9-1.5-3.9-1.5-.5-1.3-1.3-1.7-1.3-1.7-1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1 1.8 2.7 1.3 3.4 1 .1-.8.4-1.3.7-1.6-2.6-.3-5.3-1.3-5.3-5.7 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.5.1-3.1 0 0 1-.3 3.3 1.2a11.5 11.5 0 0 1 6 0C17.3 4.7 18.3 5 18.3 5c.6 1.6.2 2.8.1 3.1.8.8 1.2 1.8 1.2 3.1 0 4.4-2.7 5.4-5.3 5.7.4.4.8 1.1.8 2.2v3.3c0 .4.2.7.8.6 4.6-1.5 7.9-5.8 7.9-10.9C23.5 5.7 18.3.5 12 .5z" / >
< / svg >
GitHub
< / a >
< / div >
< / div >
2026-05-31 23:58:26 +09:00
< / div >
< / nav >
<!-- HERO -->
< header class = "hero" >
< div class = "wrap" >
< div class = "hero-logo" >
< svg viewBox = "0 0 32 32" width = "48" height = "48" aria-hidden = "true" > < path d = "M16 4L16 22L6 22Z" fill = "currentColor" / > < path d = "M16 8L16 22L24 22Z" fill = "currentColor" opacity = "0.6" / > < path d = "M4 24Q10 20 16 24Q22 28 28 24" stroke = "currentColor" stroke-width = "2.5" fill = "none" stroke-linecap = "round" / > < / svg >
< span class = "wordmark" > Odysseus< / span >
< / div >
< p class = "slogan" > Yours for the voyage.< / p >
< h1 > Your own < span class = "grad" > AI workspace< / span > ,< br > running on your hardware.< / h1 >
< p class = "lede" >
Odysseus is a self-hosted interface for talking to language models — chat,
autonomous agents, tools, model serving, email, research, and more. Local-first,
privacy-first, and no telemetry. Just you and your models.
< / p >
< p style = "font-size:11.5px; color:var(--muted); opacity:0.7; max-width:560px; margin:-18px auto 30px;" >
(if you want to add an API that's cool too — I'm not here to tell you how to live your life… )
< / p >
< div class = "hero-cta" >
< a class = "btn primary" href = "#start" > Get started< / a >
2026-06-01 10:43:35 +09:00
< a class = "btn" href = "https://github.com/pewdiepie-archdaemon/odysseus" target = "_blank" > View on GitHub< / a >
2026-05-31 23:58:26 +09:00
< / div >
< / div >
< / header >
<!-- TESTIMONIALS (gag) -->
< section id = "testimonials" style = "padding-top:30px;" >
< div class = "wrap" >
< div class = "center" >
< div class = "eyebrow" > Loved by enterprises< / div >
< h2 class = "h" > What our customers are saying< / h2 >
< / div >
< div class = "tcarousel-wrap" >
< button class = "tarrow prev" type = "button" aria-label = "Previous testimonial" > ‹ < / button >
< div class = "tgrid" id = "tcarousel" >
<!-- Coder guy -->
< figure class = "tcard" >
< span class = "av" > < img src = "https://cdn.prod.website-files.com/66708f90d7e407423093fa76/66708f91d7e407423093fd21_john-carter-testimonial-image-dentistry-x-webflow-template.png" alt = "Generic Coder Guy" loading = "lazy" > < / span >
< div class = "tmeta" >
< p class = "q" > "Odysseus helped us ship more ships while shipping ships. Truly best-in-class shipping."< / p >
< div class = "stars" > ★ ★ ★ ★ ★ < / div >
< div class = "nm" > Generic Coder Guy< / div >
< div class = "rl" > Sr. Engineer, ShipShip Inc.< / div >
< / div >
< / figure >
<!-- Woman -->
< figure class = "tcard" >
< span class = "av" > < img src = "https://images.pexels.com/photos/5876695/pexels-photo-5876695.jpeg?auto=compress&cs=tinysrgb&w=160&h=160&fit=crop" alt = "A real woman" loading = "lazy" > < / span >
< div class = "tmeta" >
< p class = "q" > "I'm a real person. This is a real testimonial. By a real woman."< / p >
< div class = "stars" > ★ ★ ★ ★ ★ < / div >
< div class = "nm" > Generic Corporate Woman< / div >
< div class = "rl" > VP of Verticals, Things LLC< / div >
< / div >
< / figure >
<!-- Cyclops -->
< figure class = "tcard cyclops" data-shake = "1" >
< span class = "av" style = "border-color:rgba(255,90,90,0.6);" >
< svg viewBox = "0 0 72 72" width = "54" height = "54" fill = "none" stroke = "#cbd5e1" stroke-width = "2" >
< rect x = "0" y = "0" width = "72" height = "72" fill = "#16241a" / >
< circle cx = "36" cy = "32" r = "18" fill = "#7fae7f" stroke = "#5a7a5a" / >
< line x1 = "29" y1 = "22" x2 = "43" y2 = "34" stroke = "#ff5a5a" stroke-width = "3" / >
< line x1 = "43" y1 = "22" x2 = "29" y2 = "34" stroke = "#ff5a5a" stroke-width = "3" / >
< ellipse cx = "36" cy = "45" rx = "7" ry = "9" fill = "#3a0a0a" stroke = "#200" / >
< path d = "M31 51 l-1 4" stroke = "#fff" stroke-width = "2" / > < path d = "M41 51 l1 4" stroke = "#fff" stroke-width = "2" / >
< / svg >
< / span >
< div class = "tmeta" >
< p class = "q" > "AHHHHHHHHHHHHHHHHHHHHHHHHHHHHH"< / p >
< div class = "stars zero" > ☆ ☆ ☆ ☆ ☆ < / div >
< div class = "nm" > Polyphemus< / div >
< div class = "rl" > Cyclops, Cave Solutions (on leave)< / div >
< / div >
< / figure >
<!-- Corporate -->
< figure class = "tcard" >
< span class = "av" >
< svg viewBox = "0 0 80 80" aria-hidden = "true" >
< rect width = "80" height = "80" rx = "18" fill = "#111827" / >
< circle cx = "40" cy = "29" r = "14" fill = "#d1d5db" / >
< path d = "M18 70c4-18 15-27 22-27s18 9 22 27" fill = "#374151" / >
< path d = "M28 58h24l-5 12H33z" fill = "#e06c75" / >
< path d = "M32 14h16l6 11H26z" fill = "#f8fafc" / >
< / svg >
< / span >
< div class = "tmeta" >
< p class = "q" > "Anyway, as I was saying — best-in-class."< / p >
< div class = "stars" > ★ ★ ★ ★ ★ < / div >
< div class = "nm" > Chad Corporate< / div >
< div class = "rl" > Chief Executive Officer< / div >
< / div >
< / figure >
< / div >
< button class = "tarrow next" type = "button" aria-label = "Next testimonial" > › < / button >
< / div >
< div class = "tnav" id = "tnav" > < / div >
< / div >
< / section >
<!-- FEATURES -->
< section id = "features" >
< div class = "wrap" >
< div class = "center" >
< div class = "eyebrow" > Everything, self-hosted< / div >
< h2 class = "h" > One app, a lot of capabilities< / h2 >
< p class = "sub" > Started as an AI chat. Became a workspace. Each piece runs locally against
whatever endpoints you point it at.< / p >
< / div >
< div class = "grid" >
< div class = "feature" >
< span class = "ico" > < svg width = "20" height = "20" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" > < path d = "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" / > < / svg > < / span >
< h3 > Chat & Agents< / h3 >
< p > Multi-turn chat plus autonomous agents that plan, call tools, and work through tasks.< / p >
< / div >
< div class = "feature" >
< span class = "ico" > < svg width = "20" height = "20" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" > < path d = "M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.8-3.8a6 6 0 0 1-7.9 7.9l-6.9 6.9a2.1 2.1 0 0 1-3-3l6.9-6.9a6 6 0 0 1 7.9-7.9z" / > < / svg > < / span >
< h3 > Tools & MCP< / h3 >
< p > Built-in tools (bash, files, web, memory) plus any MCP server you connect. Toggle per tool.< / p >
< / div >
< div class = "feature" >
< span class = "ico" > < svg width = "20" height = "20" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" > < path d = "M12 2 2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5" / > < / svg > < / span >
< h3 > Cookbook< / h3 >
< p > Hardware-aware model recommendations and one-click serving across 270+ catalogued models.< / p >
< / div >
< div class = "feature" >
< span class = "ico" > < svg width = "20" height = "20" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" > < rect x = "2" y = "4" width = "20" height = "16" rx = "2" / > < path d = "m22 7-10 5L2 7" / > < / svg > < / span >
< h3 > Email Assistant< / h3 >
< p > AI summaries, style-matched draft replies, auto-tagging and spam triage over IMAP/SMTP.< / p >
< / div >
< div class = "feature" >
< span class = "ico" > < svg width = "20" height = "20" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" > < circle cx = "11" cy = "11" r = "7" / > < path d = "M21 21l-4.3-4.3" / > < / svg > < / span >
< h3 > Deep Research< / h3 >
< p > Multi-step research runs that gather, read, and synthesize sources into a written report.< / p >
< / div >
< div class = "feature" >
< span class = "ico" > < svg width = "20" height = "20" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" > < rect x = "2" y = "3" width = "8" height = "18" rx = "1" / > < rect x = "14" y = "3" width = "8" height = "18" rx = "1" / > < / svg > < / span >
< h3 > Compare< / h3 >
< p > Send one prompt to several models at once and compare their answers side-by-side.< / p >
< / div >
< div class = "feature" >
< span class = "ico" > < svg width = "20" height = "20" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" > < ellipse cx = "12" cy = "5" rx = "9" ry = "3" / > < path d = "M3 5v14c0 1.7 4 3 9 3s9-1.3 9-3V5" / > < path d = "M3 12c0 1.7 4 3 9 3s9-1.3 9-3" / > < / svg > < / span >
< h3 > Memory< / h3 >
< p > Persistent memory the assistant builds up and recalls across all your conversations.< / p >
< / div >
< div class = "feature" >
< span class = "ico" > < svg width = "20" height = "20" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" > < path d = "M12 3l1.9 5.1L19 10l-5.1 1.9L12 17l-1.9-5.1L5 10l5.1-1.9z" / > < / svg > < / span >
< h3 > Skills < span style = "font-size:10.5px;font-weight:700;color:var(--accent);border:1px solid var(--border);border-radius:999px;padding:1px 7px;margin-left:4px;vertical-align:middle;" > self-evolving< / span > < / h3 >
< p > The assistant writes, refines, and reuses its own skills — getting more capable over time.< / p >
< / div >
< div class = "feature" >
< span class = "ico" > < svg width = "20" height = "20" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" > < rect x = "3" y = "11" width = "18" height = "11" rx = "2" / > < path d = "M7 11V7a5 5 0 0 1 10 0v4" / > < / svg > < / span >
< h3 > Private by default< / h3 >
< p > Runs on your machine against your own endpoints. No telemetry, with optional external integrations when you choose them.< / p >
< / div >
< / div >
< / div >
< / section >
<!-- The one - shot prompt it started from (gag) -->
< section style = "padding-top:0;" >
< div class = "wrap" style = "text-align:center;" >
< p class = "term-intro" > Odysseus was created by a carefully crafted one-shot AI prompt:< / p >
< div class = "term" >
< div class = "term-bar" >
< span class = "ttl" > user@odysseus: ~< / span >
< span class = "winbtns" > < span data-term = "min" title = "Minimize" > – < / span > < span class = "x" data-term = "close" title = "Close" > ✕ < / span > < / span >
< / div >
< pre id = "term-pre" > < span class = "cs" > > < / span > idk what to make can you write it for me?
actually make an ai chat, but make it good
and also make it better< / pre >
< / div >
< button class = "term-reopen" type = "button" > ✕ reopen terminal< / button >
< / div >
< / section >
<!-- PREVIEWS — hover to expand + play -->
< section id = "previews" >
< div class = "wrap" >
< div class = "center" >
< div class = "eyebrow" > See it in action< / div >
< h2 class = "h" > Hover to take a closer look< / h2 >
< p class = "sub center" > Each panel expands and plays its preview when you hover it.< / p >
< / div >
< div class = "previews" >
< div class = "preview-panel" tabindex = "0" >
< div class = "ph" > < svg width = "30" height = "30" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "1.6" stroke-linecap = "round" stroke-linejoin = "round" > < path d = "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" / > < / svg > < span > [ Chat & Agents ]< / span > < / div >
< video muted loop playsinline preload = "none" > < source src = "chat.webm" type = "video/webm" > < source src = "chat.mp4" type = "video/mp4" > < / video >
< div class = "label" > < svg class = "ico" width = "16" height = "16" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" > < path d = "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" / > < / svg > Chat & Agents< / div >
< / div >
< div class = "preview-panel" tabindex = "0" >
< div class = "ph" > < svg width = "30" height = "30" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "1.6" stroke-linecap = "round" stroke-linejoin = "round" > < path d = "M12 2 2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5" / > < / svg > < span > [ Cookbook ]< / span > < / div >
< div class = "label" > < svg class = "ico" width = "16" height = "16" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" > < path d = "M12 2 2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5" / > < / svg > Cookbook< / div >
< / div >
< div class = "preview-panel" tabindex = "0" >
< div class = "ph" > < svg width = "30" height = "30" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "1.6" stroke-linecap = "round" stroke-linejoin = "round" > < rect x = "2" y = "4" width = "20" height = "16" rx = "2" / > < path d = "m22 7-10 5L2 7" / > < / svg > < span > [ Email Assistant ]< / span > < / div >
< video muted loop playsinline preload = "none" > < source src = "email.webm" type = "video/webm" > < source src = "email.mp4" type = "video/mp4" > < / video >
< div class = "label" > < svg class = "ico" width = "16" height = "16" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" > < rect x = "2" y = "4" width = "20" height = "16" rx = "2" / > < path d = "m22 7-10 5L2 7" / > < / svg > Email Assistant< / div >
< / div >
< / div >
< / div >
< / section >
<!-- HOW IT STARTED -->
< section id = "how" >
< div class = "wrap" >
< div class = "eyebrow" > How it actually started< / div >
< h2 class = "h" > Odysseus is everything I hate, just making it tolerable.< / h2 >
< p class = "sub" style = "max-width:760px;" >
I started working on the Odysseus project because running local AI felt fun — a step into the future.
But the options to actually engage with LLMs felt like taking steps back. Where were
features like Memory, Deep Research, Agents, and just basic integrations?!
< / p >
< p class = "sub" style = "max-width:760px; margin-top:14px;" >
So I started building my own, for fun — and eventually figured it might be fun to
share what I built for myself with others. Doesn't work for you? Well… it runs
great on my hardware.
< / p >
< / div >
< / section >
<!-- GET STARTED -->
< section id = "start" >
< div class = "wrap" >
< div class = "start" >
< div class = "eyebrow" > Get started< / div >
< h2 class = "h" style = "margin-bottom:6px;" > Clone it and run< / h2 >
< p class = "sub center" style = "margin:0 auto;" > It's open source and free. No sales team, no demo request — just clone the repo.< / p >
2026-06-01 10:43:35 +09:00
< div class = "codeblock" > < span class = "prompt" > $< / span > git clone https://github.com/pewdiepie-archdaemon/odysseus.git & & cd odysseus< / div >
2026-05-31 23:58:26 +09:00
< div >
2026-06-01 10:43:35 +09:00
< a class = "btn primary" href = "https://github.com/pewdiepie-archdaemon/odysseus" target = "_blank" style = "margin-top:14px;" > View on GitHub< / a >
2026-05-31 23:58:26 +09:00
< / div >
< div class = "pill-row" >
< span class = "pill" > Self-hosted< / span >
< span class = "pill" > Bring your own models< / span >
< span class = "pill" > Local-first< / span >
< span class = "pill" > MCP-ready< / span >
< span class = "pill" > No telemetry< / span >
< / div >
< / div >
< / div >
< / section >
< footer >
< div class = "wrap" >
< div > © 2026 Odysseus · Built from one prompt that refused to stop.< / div >
< div > No cyclopes were harmed in production.< sup > *< / sup > < / div >
< / div >
< / footer >
< script >
// Typewriter for the origin terminal: type line 1, pause 2s, line 2, pause
// 2s, line 3, hold 4s, then reset and loop. Blinking "|" cursor throughout.
(function () {
var pre = document.getElementById('term-pre');
if (!pre) return;
var lines = [
{ p: '< span class = "cs" > > < / span > ', t: 'idk what to make can you write it for me?' },
{ p: ' ', t: 'actually make an ai chat, but make it good' },
{ p: ' ', t: 'and also make it better' }
];
var CURSOR = '< span class = "term-cursor" > |< / span > ';
var TYPE_MS = 40;
var done = [], li = 0, timer = null;
function render(partial) {
pre.innerHTML = done.join('\n') + (done.length ? '\n' : '') + partial + CURSOR;
}
function typeLine() {
var ln = lines[li], i = 0;
(function step() {
if (i < = ln.t.length) {
render(ln.p + ln.t.slice(0, i));
i++; timer = setTimeout(step, TYPE_MS);
} else {
done.push(ln.p + ln.t);
li++;
if (li >= lines.length) timer = setTimeout(reset, 4000); // hold last line 4s
else timer = setTimeout(typeLine, 2000); // pause 2s before next
}
})();
}
function reset() { clearTimeout(timer); done = []; li = 0; typeLine(); }
// Start typing only when the terminal scrolls into view (and replay each
// time you return to it).
if ('IntersectionObserver' in window) {
var io2 = new IntersectionObserver(function (entries) {
entries.forEach(function (e) { if (e.isIntersecting) reset(); });
}, { threshold: 0.45 });
io2.observe(pre);
} else {
reset();
}
})();
// Previews: hovering a panel expands it (CSS) and plays its video; the
// video only becomes visible once it actually starts playing, so missing
// files just leave the labeled placeholder.
(function () {
document.querySelectorAll('.preview-panel').forEach(function (p) {
var v = p.querySelector('video');
if (!v) return;
v.addEventListener('playing', function () { p.classList.add('has-video'); });
v.addEventListener('pause', function () { /* keep last frame */ });
var play = function () { var pr = v.play(); if (pr & & pr.catch) pr.catch(function () {}); };
p.addEventListener('mouseenter', play);
p.addEventListener('focus', play);
p.addEventListener('mouseleave', function () { v.pause(); });
p.addEventListener('blur', function () { v.pause(); });
p.addEventListener('click', function () { if (v.paused) play(); else v.pause(); });
});
})();
// Domino reveal: fade/slide each section in as it scrolls into view.
(function () {
var els = document.querySelectorAll('.hero, section');
if (!('IntersectionObserver' in window)) {
els.forEach(function (e) { e.classList.add('in'); });
return;
}
var io = new IntersectionObserver(function (entries) {
entries.forEach(function (e) {
if (e.isIntersecting) { e.target.classList.add('in'); io.unobserve(e.target); }
});
}, { threshold: 0.12, rootMargin: '0px 0px -8% 0px' });
els.forEach(function (e) { io.observe(e); });
})();
// Fake terminal window buttons — minimize, maximize, close (and reopen).
(function () {
var term = document.querySelector('.term');
var reopen = document.querySelector('.term-reopen');
if (!term) return;
term.querySelectorAll('.winbtns [data-term]').forEach(function (b) {
b.addEventListener('click', function () {
var act = b.getAttribute('data-term');
if (act === 'min') term.classList.toggle('term-min');
else if (act === 'close') {
term.classList.add('term-closed');
if (reopen) reopen.classList.add('show');
}
});
});
if (reopen) reopen.addEventListener('click', function () {
term.classList.remove('term-closed', 'term-min');
reopen.classList.remove('show');
});
})();
// Mobile testimonial carousel: tap or swipe to advance; Polyphemus shakes ~1s.
(function () {
var carousel = document.getElementById('tcarousel');
var nav = document.getElementById('tnav');
if (!carousel || !nav) return;
var cards = [].slice.call(carousel.querySelectorAll('.tcard'));
if (!cards.length) return;
var idx = 0;
var dots = cards.map(function (_, k) {
var d = document.createElement('span');
d.className = 'tdot';
d.addEventListener('click', function (e) { e.stopPropagation(); show(k); });
nav.appendChild(d);
return d;
});
var hint = document.createElement('div');
hint.className = 'thint';
hint.textContent = 'tap or swipe for the next satisfied customer →';
nav.appendChild(hint);
function show(i) {
idx = (i + cards.length) % cards.length;
cards.forEach(function (c, k) { c.classList.toggle('active', k === idx); c.classList.remove('shake'); });
dots.forEach(function (d, k) { d.classList.toggle('on', k === idx); });
var cur = cards[idx];
if (cur.getAttribute('data-shake') === '1') {
void cur.offsetWidth;
cur.classList.add('shake');
setTimeout(function () { cur.classList.remove('shake'); }, 1000);
}
}
carousel.addEventListener('click', function () { show(idx + 1); });
var _prev = document.querySelector('.tarrow.prev');
var _next = document.querySelector('.tarrow.next');
if (_prev) _prev.addEventListener('click', function (e) { e.stopPropagation(); show(idx - 1); });
if (_next) _next.addEventListener('click', function (e) { e.stopPropagation(); show(idx + 1); });
var sx = null;
carousel.addEventListener('touchstart', function (e) { sx = e.touches[0].clientX; }, { passive: true });
carousel.addEventListener('touchend', function (e) {
if (sx === null) return;
var dx = e.changedTouches[0].clientX - sx;
if (Math.abs(dx) > 30) { show(idx + (dx < 0 ? 1 : -1 ) ) ; }
sx = null;
});
show(0);
})();
2026-06-01 15:57:01 +04:00
// Mobile navigation: open/close hamburger menu
(function () {
var container = document.querySelector('.nav-links-hamburger');
if (!container) return;
var button = container.querySelector('.hamburger-btn');
button.addEventListener('click', function (e) {
e.stopPropagation();
container.classList.toggle('open');
});
document.addEventListener('click', function () {
container.classList.remove('open');
});
})();
2026-05-31 23:58:26 +09:00
< / script >
< / body >
< / html >