Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,16 @@ export default defineConfig({
provider: fontProviders.google(),
name: "Doto",
cssVariable: "--font-main",
weights: [400, 700],
weights: [400, 500, 700],
styles: ["normal"],
subsets: ["latin"],
display: "swap",
},
{
provider: fontProviders.google(),
name: "JetBrains Mono",
cssVariable: "--font-body",
weights: [300, 400, 500],
styles: ["normal"],
subsets: ["latin"],
display: "swap",
Expand Down
390 changes: 390 additions & 0 deletions docs/plans/2026-06-02-experience-site-revamp-design.md

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions public/humans.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* TEAM */

the experience company
hackers · engineers · designers

/* WHAT WE'RE BUILDING */

gaia ............... personal AI assistant — live → heygaia.io
smart glasses ...... in development
household robotics . on the horizon

/* SAY HI */

hi@heygaia.io

the screen was just where we started.
Binary file added public/img/figure.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/gaia.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/glasses.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/march.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/touch.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 37 additions & 0 deletions src/components/sections/Close.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
import Section from "../ui/Section.astro";
import { siteConfig } from "../../config/site";

const twitter = siteConfig.social.twitter?.replace("@", "");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Don't render the X link from an optional handle.

siteConfig.social.twitter is treated as optional here, but the anchor always renders. If that config is missing, this ships https://twitter.com/undefined as a broken contact link.

Proposed fix
 const twitter = siteConfig.social.twitter?.replace("@", "");
---
-      <a
-        class="link-bracket"
-        href={`https://twitter.com/${twitter}`}
-        target="_blank"
-        rel="noopener"
-      >
-        x
-      </a>
+      {twitter && (
+        <a
+          class="link-bracket"
+          href={`https://twitter.com/${twitter}`}
+          target="_blank"
+          rel="noopener"
+        >
+          x
+        </a>
+      )}

Also applies to: 27-34

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/sections/Close.astro` at line 5, The X/Twitter anchor in
Close.astro is always rendered even when siteConfig.social.twitter is missing,
which produces a broken undefined link. Update the Close component so the
twitter handle is only normalized and rendered when the optional config value
exists, and otherwise omit the link block entirely; use the existing twitter
variable and the anchor section around the social links to gate the output.

---

<Section index="06">
<blockquote cite="https://en.wikipedia.org/wiki/Steve_Jobs">
"The people who are crazy enough to think they can change the world are the
ones who do."
<cite>— Steve Jobs</cite>
</blockquote>

<div class="contact">
<p class="prose">If you want to help build this, we'd love to meet you.</p>
<div class="links">
<a class="link-bracket" href={`mailto:${siteConfig.social.email}`}>email</a>
<a
class="link-bracket"
href={`https://github.com/${siteConfig.social.github}`}
target="_blank"
rel="noopener"
>
github
</a>
<a
class="link-bracket"
href={`https://twitter.com/${twitter}`}
target="_blank"
rel="noopener"
>
x
</a>
</div>
</div>
</Section>
30 changes: 30 additions & 0 deletions src/components/sections/Connection.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
import Section from "../ui/Section.astro";
import ImageFrame from "../ui/ImageFrame.astro";
---

<Section index="05" class="connect">
<div class="stack fullbleed">
<ImageFrame
src="/img/march.webp"
alt="the march of progress — human to machine"
label="march of progress"
size="wide"
/>
<ImageFrame
src="/img/touch.webp"
alt="human and robot hands almost touching"
label="the touch — creation of adam"
size="wide"
/>
</div>

<p class="payoff">
People ask why a software company is building glasses and robots. We don't
really think of ourselves as a software company. We think most of what fills
your day — the digital admin, the errands, the housework — is work you never
should have been doing. GAIA takes the digital load. The glasses carry it
with you. Robots take the physical load at home.
<span class="last">The screen was just where we started.</span>
</p>
</Section>
42 changes: 42 additions & 0 deletions src/components/sections/Gaia.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
import Section from "../ui/Section.astro";
import ImageFrame from "../ui/ImageFrame.astro";
---

<Section index="02">
<div class="label">
<span class="name">gaia</span>
<span class="status live"><span class="live-dot"></span>live today</span>
</div>

<div class="media-block">
<ImageFrame
src="/img/gaia.webp"
alt="GAIA — wireframe planet"
label="wireframe planet"
caption="fig. 01 — gaia"
/>
</div>

<p class="lead">
Most assistants wait for you to ask, then forget you the second you close
the tab. GAIA doesn't.
</p>
<p class="prose">
It reads your inbox before you do, watches your calendar, drafts your
replies, and runs the multi-step work you'd never get around to — then
remembers all of it, so it's sharper next month than it is today.
</p>
<p class="prose">
It's live, open source, and already doing this.
<a class="link-inline" href="https://heygaia.io" target="_blank" rel="noopener"
>→ heygaia.io</a
>
</p>
<p class="prose">
Where it's headed: off the screen and onto your body. Paired with the
glasses, GAIA goes everywhere you go — the goal is simple, and a little
unreasonable: an assistant that can handle anything you'd handle yourself.
Everyone deserves a Jarvis.
</p>
</Section>
10 changes: 10 additions & 0 deletions src/components/sections/Hero.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
import Section from "../ui/Section.astro";
---

<Section index="00" class="hero">
<h1>We build technology that makes people more capable.</h1>
<p class="sub">Technology should give you your life back.</p>
<p class="sub">We're building a better experience for being human.</p>
<div class="cue">↓ scroll</div>
</Section>
29 changes: 29 additions & 0 deletions src/components/sections/Manifesto.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
import Section from "../ui/Section.astro";
import ImageFrame from "../ui/ImageFrame.astro";
---

<Section index="01">
<p class="lead">
We're a small team of hackers, engineers, and designers. We build the things
we wish existed.
</p>
<p class="prose">
We think the best technology gives you more and asks for less — more time,
more attention, more room to be human — and then gets out of the way. Most
technology today does the opposite. We're building the other kind.
</p>
<p class="prose">
Everything worth building looks impossible right up until someone builds it.
That's the part we like.
</p>

<div class="media-block" style="margin-top: 44px">
<ImageFrame
src="/img/figure.webp"
alt="human becoming machine"
label="human → machine"
caption="fig. 00 — the human"
/>
</div>
</Section>
21 changes: 21 additions & 0 deletions src/components/sections/Robotics.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
import Section from "../ui/Section.astro";
---

<Section index="04">
<div class="label">
<span class="name">household robotics</span>
<span class="status">on the horizon</span>
</div>

<p class="prose">
We're also drawn to what comes after the screen. AI learned to make art and
music — the parts of being human we'd least want to give up — while the
laundry still piles up. That feels backwards. The boring, physical work is
exactly what machines should take off our hands.
</p>
<p class="prose">
We haven't started building it. It's just a future we believe in — and
probably the hardest thing we'll ever attempt.
</p>
</Section>
62 changes: 62 additions & 0 deletions src/components/sections/SmartGlasses.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
import Section from "../ui/Section.astro";
import ImageFrame from "../ui/ImageFrame.astro";
import Redacted from "../ui/Redacted.astro";

const specs = [
{ k: "display", v: "visible only to you" },
{ k: "voice", v: '"hey gaia"' },
{ k: "navigation", v: "painted on the road, live" },
{ k: "memory", v: "auto-captures what matters" },
{ k: "control", v: "voice · eyes · blink · hands" },
{ k: "audio", v: "bone conduction" },
{ k: "lenses", v: "clear → sunglasses, one press" },
{ k: "power", v: "solar across the frame" },
{ k: "build", v: "light, affordable, not ugly" },
];
---

<Section index="03">
<div class="label">
<span class="name">smart glasses</span>
<span class="status">in development</span>
</div>

<ImageFrame
src="/img/glasses.webp"
alt="smart glasses — front blueprint"
label="smart glasses blueprint"
caption="fig. 02 — front elevation"
size="wide"
/>

<p class="lead" style="margin-top:34px">
GAIA, on your face. A display only you can see, a camera that sees what you
see, and an assistant you just talk to. It paints your directions onto the
road ahead, picks up the call you don't want to take, and remembers the
things you'd have forgotten by dinner. You run it with your voice, your
eyes, and your hands — no controller, no phone in your palm.
</p>
<p class="prose" style="margin-top:18px">
Most smart glasses are bricks you'd never wear in public. These are meant to
be light, cheap, and good-looking enough that you forget they're smart at
all.
</p>

<div class="specs">
{
specs.map((s) => (
<div class="spec">
<span class="k">{s.k}</span>
<span class="dots" />
<span class="v">{s.v}</span>
</div>
))
}
<div class="spec">
<span class="k">field of view</span>
<span class="dots"></span>
<span class="v"><Redacted text="classified" /></span>
</div>
</div>
</Section>
35 changes: 35 additions & 0 deletions src/components/ui/ImageFrame.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
interface Props {
/** drop in a real image path (e.g. /glasses.webp) to replace the placeholder */
src?: string;
alt?: string;
/** placeholder label shown until a real image exists */
label: string;
/** small blueprint caption under the frame, e.g. "fig. 01 — smart glasses" */
caption?: string;
size?: "wide" | "tall";
class?: string;
}

const {
src,
alt = "",
label,
caption,
size = "tall",
Comment on lines +16 to +19

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve an accessible name when src is used.

Line 16 defaults alt to "", and the image branch on Line 27 drops the required label. The first real asset added through this component will render as decorative unless every caller remembers to supply a separate alt.

Suggested fix
 const {
   src,
-  alt = "",
+  alt,
   label,
   caption,
   size = "tall",
   class: cls = "",
 } = Astro.props as Props;
@@
-        <img src={src} alt={alt} loading="lazy" decoding="async" />
+        <img src={src} alt={alt ?? label} loading="lazy" decoding="async" />

Also applies to: 27-28

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/ui/ImageFrame.astro` around lines 16 - 19, The ImageFrame
component is defaulting alt to an empty string and the image render path is not
preserving an accessible name when src is used. Update ImageFrame.astro so the
Image branch uses the provided label as the default accessible text (or
otherwise requires a meaningful alt/label pairing) instead of silently rendering
decorative images. Keep the fix localized to the ImageFrame props/defaults and
the image rendering logic so callers don’t have to remember to supply both
fields.

class: cls = "",
} = Astro.props as Props;
---

<figure class:list={["frame-fig", cls]}>
<div class:list={["box", size, src && "has-img"]}>
{
src ? (
<img src={src} alt={alt} loading="lazy" decoding="async" />
) : (
<span>[ {label} ]</span>
)
}
</div>
{caption && <figcaption>{caption}</figcaption>}
</figure>
11 changes: 11 additions & 0 deletions src/components/ui/Redacted.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
interface Props {
/** text to hide behind the bar; also the screen-reader value */
children?: never;
text?: string;
}

const { text = "classified" } = Astro.props as Props;
---

<span class="redacted" title="classified">{text}</span>
14 changes: 14 additions & 0 deletions src/components/ui/Section.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
interface Props {
index?: string;
id?: string;
class?: string;
}

const { index, id, class: cls = "" } = Astro.props as Props;
---

<section id={id} class:list={["section", cls]}>
{index && <span class="sec-index" aria-hidden="true">{index}</span>}
<slot />
</section>
Loading