diff --git a/index.html b/index.html
index 015b751..8f16d19 100644
--- a/index.html
+++ b/index.html
@@ -24,72 +24,65 @@
What if an AI companion wasn't just an app, but something physical in your room? CipherDolls is my biggest project: an AI companion platform where characters can talk, listen — and live inside real devices.
github.com/cipherdolls ↗
-
+
-
- core
- The brain of the platform: one backend that handles chat, voice, memory, payments and the connection to the physical dolls.
+ -
+
+
The brain of the platform: one backend that handles chat, voice, memory, payments and the connection to the physical dolls.
- View on GitHub ↗
-
+
-
- server
- A slimmed-down core for anyone who just wants to chat with a character — the same architecture, none of the complexity.
+ -
+
+
A slimmed-down core for anyone who just wants to chat with a character — the same architecture, none of the complexity.
- View on GitHub ↗
-
+
-
- webapp
- The web face of CipherDolls — where you meet the characters.
+ -
+
+
The web face of CipherDolls — where you meet the characters.
- View on GitHub ↗
-
+
-
- stream-player
- Voices need to arrive instantly. This streams the AI's speech to your browser the moment it is generated.
+ -
+
+
Voices need to arrive instantly. This streams the AI's speech to your browser the moment it is generated.
- View on GitHub ↗
-
+
-
- stream-recorder
- The listening half: your voice streams in, gets converted on the fly, and lands with the AI.
+ -
+
+
The listening half: your voice streams in, gets converted on the fly, and lands with the AI.
- View on GitHub ↗
-
+
-
- firmware-watcher
- The magic moment: a real device on your desk wakes up, connects, and speaks with the character's voice.
+ -
+
+
The magic moment: a real device on your desk wakes up, connects, and speaks with the character's voice.
- View on GitHub ↗
-
+
-
- firmware-m5sticks3
- The pocket version: the same companion on a tiny stick with a display and a microphone.
+ -
+
+
The pocket version: the same companion on a tiny stick with a display and a microphone.
- View on GitHub ↗
-
+
-
+
@@ -98,63 +91,57 @@
Decentralized apps — Gnosis Chain + Ethereum Swarm
Can the web run without servers? These apps are my experiments in building things that nobody can switch off.
-
+
-
- SwarmChat
- I was thinking about how cool it would be to have a web3-based chat system. Is it possible to communicate without any servers? With Swarm, a decentralised technology, this is now possible — messages travel encrypted through the network itself, and your wallet is your identity.
+ -
+
+
I was thinking about how cool it would be to have a web3-based chat system. Is it possible to communicate without any servers? With Swarm, a decentralised technology, this is now possible — messages travel encrypted through the network itself, and your wallet is your identity.
- View on GitHub ↗
-
+
-
- Pink Chainsaw
- I wanted an imageboard where content can't just disappear. Images live on Swarm, and every post pays a little to keep them alive — good content earns you cheaper posting, bad content gets expensive.
+ -
+
+
I wanted an imageboard where content can't just disappear. Images live on Swarm, and every post pays a little to keep them alive — good content earns you cheaper posting, bad content gets expensive.
- View on GitHub ↗
-
+
-
- FreeeMarket
- Can you run a marketplace with no company behind it? Anyone opens a shop, buyers pay in stablecoins, and on-chain escrow replaces the middleman. Deliberately fee-free — a farmers' market for the internet.
+ -
+
+
Can you run a marketplace with no company behind it? Anyone opens a shop, buyers pay in stablecoins, and on-chain escrow replaces the middleman. Deliberately fee-free — a farmers' market for the internet.
- View on GitHub ↗
-
+
-
- WalletMatrix
- My tokens were scattered across a dozen chains and I could never see the whole picture. So I built a pivot table for your wallet: tokens as rows, chains as columns — drag a cell from one chain to another to bridge.
+ -
+
+
My tokens were scattered across a dozen chains and I could never see the whole picture. So I built a pivot table for your wallet: tokens as rows, chains as columns — drag a cell from one chain to another to bridge.
- View on GitHub ↗
-
+
-
- swarm-connect
- Every Swarm dApp I built needed the same onboarding dance: wallet, network, Bee node, postage stamp. So I packaged it once — a single React button that walks users through all of it.
+ -
+
+
Every Swarm dApp I built needed the same onboarding dance: wallet, network, Bee node, postage stamp. So I packaged it once — a single React button that walks users through all of it.
- View on GitHub ↗
-
+
-
- opentab
- An experiment with onchain apps on Base.
+ -
+
+
An experiment with onchain apps on Base.
- View on GitHub ↗
-
+
-
+
@@ -163,36 +150,33 @@
AI on GPU — self-hosted speech services
I wanted my projects to hear and speak without sending a single word to the cloud — so these run on my own GPU.
-
+
-
- whisper-cuda
- Speech-to-text on my own GPU: no cloud, no per-minute pricing. Whisper packaged for the RTX 5090 so anything in my homelab can transcribe audio locally.
+ -
+
+
Speech-to-text on my own GPU: no cloud, no per-minute pricing. Whisper packaged for the RTX 5090 so anything in my homelab can transcribe audio locally.
- View on GitHub ↗
-
+
-
- kokoro-cuda
- Giving my projects a voice: a small self-hosted TTS service with 49 voices in 9 languages, fast enough to stream. Type text, hear it instantly.
+ -
+
+
Giving my projects a voice: a small self-hosted TTS service with 49 voices in 9 languages, fast enough to stream. Type text, hear it instantly.
- View on GitHub ↗
-
+
-
- voxtral-cuda
- The newest open speech models are amazing but heavy. This runs Mistral's Voxtral on a local GPU, so state-of-the-art speech stays in my own house.
+ -
+
+
The newest open speech models are amazing but heavy. This runs Mistral's Voxtral on a local GPU, so state-of-the-art speech stays in my own house.
- View on GitHub ↗
-
+
-
+
@@ -200,18 +184,17 @@
Ethereum infrastructure
-
+
diff --git a/styles.css b/styles.css
index 4acb9d6..658b945 100644
--- a/styles.css
+++ b/styles.css
@@ -2,12 +2,8 @@
--fg: #e6edf3;
--muted: #9198a1;
--bg: #0d1117;
- --bg-elev: #161b22;
--accent: #58a6ff;
--border: #30363d;
- --tag-bg: #1f2630;
- --tag-fg: #8a929e;
- --radius: 12px;
--maxw: 64rem;
}
@@ -16,11 +12,8 @@
--fg: #1f2328;
--muted: #57606a;
--bg: #ffffff;
- --bg-elev: #f6f8fa;
--accent: #0969da;
--border: #d0d7de;
- --tag-bg: #eaeef2;
- --tag-fg: #57606a;
}
}
@@ -90,69 +83,56 @@ body {
}
.section-link:hover { text-decoration: underline; }
-/* Cards grid */
-.cards {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
- gap: 1.25rem;
+/* Projects — simple single-column list */
+.projects {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ max-width: 42rem;
}
-
-.card {
- display: flex;
- flex-direction: column;
- background: var(--bg-elev);
- border: 1px solid var(--border);
- border-radius: var(--radius);
- padding: 1.5rem 1.4rem 1.4rem;
- transition: border-color 0.15s ease;
+.project {
+ padding: 1.5rem 0;
+ border-bottom: 1px solid var(--border);
}
-.card:hover { border-color: var(--accent); }
-.card:focus-within { border-color: var(--accent); }
-
-.card-name {
- margin: 0 0 0.75rem;
- font-size: 1.1rem;
+.project:last-child { border-bottom: none; }
+.project-name {
+ margin: 0 0 0.4rem;
+ font-size: 1.15rem;
font-weight: 700;
letter-spacing: -0.01em;
}
-.card-story {
- margin: 0.5rem 0 1.1rem;
+.project-name a {
+ color: var(--accent);
+ text-decoration: none;
+}
+.project-name a:hover { text-decoration: underline; }
+.project-story {
+ margin: 0 0 0.6rem;
color: var(--fg);
font-size: 1.02rem;
line-height: 1.65;
- flex: 1 1 auto;
}
/* Tags — small, muted detail */
.tags {
list-style: none;
- margin: 0 0 0.85rem;
+ margin: 0;
padding: 0;
display: flex;
flex-wrap: wrap;
gap: 0.35rem;
}
.tags li {
- font-size: 0.7rem;
+ font-size: 0.75rem;
line-height: 1.4;
- color: var(--tag-fg);
- background: var(--tag-bg);
- border: 1px solid var(--border);
- border-radius: 999px;
- padding: 0.1rem 0.5rem;
- white-space: nowrap;
- opacity: 0.95;
-}
-
-/* Card link — subtle, sits below the story */
-.card-link {
- align-self: flex-start;
color: var(--muted);
- text-decoration: none;
- font-size: 0.82rem;
- font-weight: 500;
+ white-space: nowrap;
+}
+.tags li:not(:last-child)::after {
+ content: "·";
+ margin-left: 0.35rem;
+ color: var(--border);
}
-.card-link:hover { color: var(--accent); text-decoration: underline; }
/* Footer */
.site-footer {
@@ -189,9 +169,6 @@ a:focus-visible {
/* Responsive tightening on small screens */
@media (max-width: 30rem) {
- .cards {
- grid-template-columns: 1fr;
- }
.site-header { padding: 2rem 0 1.25rem; }
.section { padding: 2rem 0 0.5rem; }
}
\ No newline at end of file