|
7 | 7 | <h2 class="reveal">One stack, zero friction</h2> |
8 | 8 | <p class="section-sub reveal">Each tool solves a distinct problem. Together they cover the full cost of AI-assisted development.</p> |
9 | 9 |
|
10 | | - <div class="flow reveal"> |
11 | | - <div class="flow-col"> |
12 | | - <div class="flow-label">Your editor sends a request</div> |
13 | | - <div class="flow-node editor-node"> |
14 | | - <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> |
| 10 | + <div class="eco-layout reveal"> |
| 11 | + |
| 12 | + <!-- Left: flow diagram --> |
| 13 | + <div class="eco-flow"> |
| 14 | + <div class="flow-node node-editor"> |
| 15 | + <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> |
15 | 16 | <rect x="2" y="3" width="20" height="14" rx="2"/><polyline points="8 21 12 17 16 21"/> |
16 | 17 | </svg> |
17 | | - Claude Code · Cursor · Windsurf |
| 18 | + Your editor |
18 | 19 | </div> |
19 | | - </div> |
20 | 20 |
|
21 | | - <div class="flow-arrow">↓</div> |
| 21 | + <div class="flow-connector"> |
| 22 | + <div class="connector-line"></div> |
| 23 | + <div class="connector-branches"> |
| 24 | + <div class="branch branch-left"> |
| 25 | + <div class="branch-line"></div> |
| 26 | + <div class="flow-node node-tool" data-tool="trimcp">trimcp</div> |
| 27 | + </div> |
| 28 | + <div class="branch branch-right"> |
| 29 | + <div class="branch-line"></div> |
| 30 | + <div class="flow-node node-tool" data-tool="tersify">tersify</div> |
| 31 | + </div> |
| 32 | + </div> |
| 33 | + </div> |
22 | 34 |
|
23 | | - <div class="flow-row"> |
24 | | - <div class="flow-tool"> |
25 | | - <div class="tool-chip chip-rust">trimcp</div> |
26 | | - <p>MCP tool outputs compressed before they reach the model</p> |
27 | | - <span class="tool-stat">−60–90% tokens on MCP responses</span> |
| 35 | + <div class="flow-connector"> |
| 36 | + <div class="connector-branches"> |
| 37 | + <div class="branch branch-left"> |
| 38 | + <div class="branch-line"></div> |
| 39 | + <div class="flow-node node-tool" data-tool="semtree">semtree</div> |
| 40 | + </div> |
| 41 | + <div class="branch branch-right"> |
| 42 | + <div class="branch-line"></div> |
| 43 | + <div class="flow-node node-tool" data-tool="aimemo">aimemo</div> |
| 44 | + </div> |
| 45 | + </div> |
| 46 | + <div class="connector-line"></div> |
28 | 47 | </div> |
29 | | - <div class="flow-tool"> |
30 | | - <div class="tool-chip chip-rust">tersify</div> |
31 | | - <p>Code and text stripped of noise before being sent</p> |
32 | | - <span class="tool-stat">−50% tokens on code context</span> |
| 48 | + |
| 49 | + <div class="flow-node node-result"> |
| 50 | + <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> |
| 51 | + <polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/> |
| 52 | + </svg> |
| 53 | + Faster · cheaper · smarter |
33 | 54 | </div> |
34 | 55 | </div> |
35 | 56 |
|
36 | | - <div class="flow-arrow">↓</div> |
37 | | - |
38 | | - <div class="flow-row"> |
39 | | - <div class="flow-tool"> |
40 | | - <div class="tool-chip chip-rust">semtree</div> |
41 | | - <p>Codebase parsed and indexed semantically with tree-sitter</p> |
42 | | - <span class="tool-stat">Precise context — only what's relevant</span> |
| 57 | + <!-- Right: tool descriptions --> |
| 58 | + <div class="eco-details"> |
| 59 | + <div class="eco-item" data-tool="trimcp"> |
| 60 | + <div class="eco-name">trimcp</div> |
| 61 | + <p>MCP tool outputs compressed before they reach the model.</p> |
| 62 | + <span class="eco-stat">−60–90% tokens on MCP responses</span> |
43 | 63 | </div> |
44 | | - <div class="flow-tool"> |
45 | | - <div class="tool-chip chip-rust">aimemo</div> |
46 | | - <p>Decisions, conventions, and tasks remembered across sessions</p> |
47 | | - <span class="tool-stat">No repeated explanations</span> |
| 64 | + <div class="eco-item" data-tool="tersify"> |
| 65 | + <div class="eco-name">tersify</div> |
| 66 | + <p>Code and text stripped of noise before being sent.</p> |
| 67 | + <span class="eco-stat">−50% tokens on code context</span> |
| 68 | + </div> |
| 69 | + <div class="eco-item" data-tool="semtree"> |
| 70 | + <div class="eco-name">semtree</div> |
| 71 | + <p>Codebase indexed semantically — only relevant code injected.</p> |
| 72 | + <span class="eco-stat">Precise context, no noise</span> |
| 73 | + </div> |
| 74 | + <div class="eco-item" data-tool="aimemo"> |
| 75 | + <div class="eco-name">aimemo</div> |
| 76 | + <p>Decisions and conventions remembered across sessions.</p> |
| 77 | + <span class="eco-stat">No repeated explanations</span> |
48 | 78 | </div> |
49 | | - </div> |
50 | | - |
51 | | - <div class="flow-arrow">↓</div> |
52 | 79 |
|
53 | | - <div class="flow-col"> |
54 | | - <div class="flow-label">The model gets what it needs — nothing more</div> |
55 | | - <div class="flow-node result-node"> |
56 | | - <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> |
57 | | - <polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/> |
58 | | - </svg> |
59 | | - Faster · cheaper · smarter completions |
| 80 | + <div class="eco-note"> |
| 81 | + <span class="note-tag">Also standalone</span> |
| 82 | + <span><a href="/projects/semstore">semstore</a> is the vector store powering semtree — available as a library for any Rust app.</span> |
60 | 83 | </div> |
61 | 84 | </div> |
62 | | - </div> |
63 | 85 |
|
64 | | - <div class="also-note reveal"> |
65 | | - <span class="note-label">Also standalone</span> |
66 | | - <span class="note-text"> |
67 | | - <a href="/projects/semstore">semstore</a> is the vector store powering semtree — available as a library to build your own semantic search into any Rust app. |
68 | | - </span> |
69 | 86 | </div> |
70 | 87 | </div> |
71 | 88 | </section> |
|
76 | 93 | border-bottom: 1px solid var(--border); |
77 | 94 | } |
78 | 95 |
|
79 | | - .flow { |
| 96 | + .eco-layout { |
80 | 97 | margin-top: 3rem; |
81 | | - display: flex; |
82 | | - flex-direction: column; |
| 98 | + display: grid; |
| 99 | + grid-template-columns: 1fr 1fr; |
| 100 | + gap: 4rem; |
83 | 101 | align-items: center; |
84 | | - gap: 0; |
85 | 102 | } |
86 | 103 |
|
87 | | - .flow-arrow { |
88 | | - font-size: 1.25rem; |
89 | | - color: var(--rust-dim); |
90 | | - padding: 0.75rem 0; |
91 | | - line-height: 1; |
92 | | - } |
93 | | - |
94 | | - .flow-col { |
| 104 | + /* Flow diagram */ |
| 105 | + .eco-flow { |
95 | 106 | display: flex; |
96 | 107 | flex-direction: column; |
97 | 108 | align-items: center; |
98 | | - gap: 0.75rem; |
99 | | - width: 100%; |
100 | | - max-width: 600px; |
101 | | - } |
102 | | - |
103 | | - .flow-label { |
104 | | - font-family: 'IBM Plex Mono', monospace; |
105 | | - font-size: 0.72rem; |
106 | | - color: var(--text-dim); |
107 | | - text-transform: uppercase; |
108 | | - letter-spacing: 0.1em; |
| 109 | + gap: 0; |
| 110 | + user-select: none; |
109 | 111 | } |
110 | 112 |
|
111 | 113 | .flow-node { |
112 | 114 | display: inline-flex; |
113 | 115 | align-items: center; |
114 | | - gap: 0.6rem; |
115 | | - padding: 0.65rem 1.5rem; |
| 116 | + gap: 0.5rem; |
| 117 | + padding: 0.55rem 1.25rem; |
116 | 118 | border-radius: 4px; |
117 | 119 | font-family: 'IBM Plex Mono', monospace; |
118 | | - font-size: 0.82rem; |
119 | | - width: 100%; |
120 | | - max-width: 480px; |
121 | | - justify-content: center; |
| 120 | + font-size: 0.8rem; |
| 121 | + white-space: nowrap; |
| 122 | + position: relative; |
| 123 | + z-index: 1; |
122 | 124 | } |
123 | 125 |
|
124 | | - .editor-node { |
| 126 | + .node-editor { |
125 | 127 | background: var(--bg-2); |
126 | 128 | border: 1px solid var(--border-hi); |
127 | 129 | color: var(--text-muted); |
128 | 130 | } |
129 | 131 |
|
130 | | - .result-node { |
| 132 | + .node-result { |
131 | 133 | background: var(--rust-glow); |
132 | 134 | border: 1px solid var(--rust-dim); |
133 | 135 | color: var(--rust); |
134 | 136 | } |
135 | 137 |
|
136 | | - .flow-row { |
137 | | - display: grid; |
138 | | - grid-template-columns: 1fr 1fr; |
139 | | - gap: 1px; |
| 138 | + .node-tool { |
| 139 | + background: var(--bg-3); |
| 140 | + border: 1px solid var(--border); |
| 141 | + color: var(--text-dim); |
| 142 | + font-weight: 500; |
| 143 | + letter-spacing: -0.01em; |
| 144 | + transition: border-color 0.2s, color 0.2s, background 0.2s; |
| 145 | + cursor: default; |
| 146 | + } |
| 147 | + |
| 148 | + .node-tool.active, |
| 149 | + .node-tool:hover { |
| 150 | + border-color: var(--rust-dim); |
| 151 | + color: var(--rust); |
| 152 | + background: var(--rust-glow); |
| 153 | + } |
| 154 | + |
| 155 | + .flow-connector { |
| 156 | + display: flex; |
| 157 | + flex-direction: column; |
| 158 | + align-items: center; |
140 | 159 | width: 100%; |
141 | | - max-width: 700px; |
| 160 | + max-width: 260px; |
| 161 | + } |
| 162 | + |
| 163 | + .connector-line { |
| 164 | + width: 1px; |
| 165 | + height: 20px; |
| 166 | + background: var(--border); |
| 167 | + } |
| 168 | + |
| 169 | + .connector-branches { |
| 170 | + display: flex; |
| 171 | + width: 100%; |
| 172 | + justify-content: center; |
| 173 | + gap: 0; |
| 174 | + } |
| 175 | + |
| 176 | + .branch { |
| 177 | + display: flex; |
| 178 | + flex-direction: column; |
| 179 | + align-items: center; |
| 180 | + flex: 1; |
| 181 | + } |
| 182 | + |
| 183 | + .branch-line { |
| 184 | + width: 1px; |
| 185 | + height: 20px; |
142 | 186 | background: var(--border); |
| 187 | + } |
| 188 | + |
| 189 | + /* Details panel */ |
| 190 | + .eco-details { |
| 191 | + display: flex; |
| 192 | + flex-direction: column; |
| 193 | + gap: 0; |
143 | 194 | border: 1px solid var(--border); |
144 | 195 | border-radius: 6px; |
145 | 196 | overflow: hidden; |
146 | 197 | } |
147 | 198 |
|
148 | | - .flow-tool { |
149 | | - background: var(--bg-2); |
150 | | - padding: 1.25rem 1.5rem; |
151 | | - display: flex; |
152 | | - flex-direction: column; |
153 | | - gap: 0.5rem; |
| 199 | + .eco-item { |
| 200 | + padding: 1rem 1.25rem; |
| 201 | + border-bottom: 1px solid var(--border); |
| 202 | + transition: background 0.2s; |
| 203 | + cursor: default; |
154 | 204 | } |
155 | 205 |
|
156 | | - .tool-chip { |
| 206 | + .eco-item:last-of-type { border-bottom: none; } |
| 207 | + .eco-item:hover, |
| 208 | + .eco-item.active { background: var(--bg-3); } |
| 209 | + |
| 210 | + .eco-name { |
157 | 211 | font-family: 'Space Mono', monospace; |
158 | | - font-size: 0.78rem; |
| 212 | + font-size: 0.82rem; |
159 | 213 | font-weight: 700; |
| 214 | + color: var(--rust); |
160 | 215 | letter-spacing: -0.02em; |
161 | | - display: inline-block; |
162 | | - margin-bottom: 0.25rem; |
| 216 | + margin-bottom: 0.3rem; |
163 | 217 | } |
164 | 218 |
|
165 | | - .chip-rust { color: var(--rust); } |
166 | | - |
167 | | - .flow-tool p { |
| 219 | + .eco-item p { |
168 | 220 | font-size: 0.82rem; |
169 | 221 | color: var(--text-muted); |
170 | | - line-height: 1.6; |
171 | | - margin: 0; |
| 222 | + line-height: 1.55; |
| 223 | + margin: 0 0 0.4rem; |
172 | 224 | } |
173 | 225 |
|
174 | | - .tool-stat { |
| 226 | + .eco-stat { |
175 | 227 | font-family: 'IBM Plex Mono', monospace; |
176 | | - font-size: 0.7rem; |
| 228 | + font-size: 0.68rem; |
177 | 229 | color: var(--text-dim); |
178 | | - border-top: 1px solid var(--border); |
179 | | - padding-top: 0.5rem; |
180 | | - margin-top: 0.25rem; |
| 230 | + letter-spacing: 0.02em; |
181 | 231 | } |
182 | 232 |
|
183 | | - .also-note { |
184 | | - margin-top: 2.5rem; |
| 233 | + .eco-note { |
| 234 | + padding: 0.85rem 1.25rem; |
| 235 | + background: var(--bg-2); |
| 236 | + border-top: 1px solid var(--border); |
185 | 237 | display: flex; |
| 238 | + gap: 0.6rem; |
186 | 239 | align-items: baseline; |
187 | | - gap: 0.75rem; |
188 | | - padding: 1rem 1.5rem; |
189 | | - background: var(--bg-2); |
190 | | - border: 1px solid var(--border); |
191 | | - border-radius: 4px; |
192 | | - max-width: 700px; |
193 | | - width: 100%; |
| 240 | + flex-wrap: wrap; |
| 241 | + font-size: 0.8rem; |
| 242 | + color: var(--text-muted); |
| 243 | + line-height: 1.5; |
194 | 244 | } |
195 | 245 |
|
196 | | - .note-label { |
| 246 | + .note-tag { |
197 | 247 | font-family: 'IBM Plex Mono', monospace; |
198 | | - font-size: 0.68rem; |
| 248 | + font-size: 0.65rem; |
199 | 249 | text-transform: uppercase; |
200 | 250 | letter-spacing: 0.1em; |
201 | 251 | color: var(--rust); |
202 | 252 | white-space: nowrap; |
203 | 253 | flex-shrink: 0; |
204 | 254 | } |
205 | 255 |
|
206 | | - .note-text { |
207 | | - font-size: 0.85rem; |
208 | | - color: var(--text-muted); |
209 | | - line-height: 1.6; |
210 | | - } |
| 256 | + .eco-note a { color: var(--rust); text-decoration: none; } |
| 257 | + .eco-note a:hover { text-decoration: underline; } |
211 | 258 |
|
212 | | - .note-text a { |
213 | | - color: var(--rust); |
214 | | - text-decoration: none; |
| 259 | + @media (max-width: 860px) { |
| 260 | + .eco-layout { grid-template-columns: 1fr; gap: 2rem; } |
| 261 | + .eco-flow { display: none; } |
215 | 262 | } |
| 263 | +</style> |
216 | 264 |
|
217 | | - .note-text a:hover { text-decoration: underline; } |
| 265 | +<script> |
| 266 | + // Sync hover between flow nodes and detail items |
| 267 | + const tools = ['trimcp', 'tersify', 'semtree', 'aimemo']; |
218 | 268 |
|
219 | | - @media (max-width: 640px) { |
220 | | - .flow-row { grid-template-columns: 1fr; } |
221 | | - .also-note { flex-direction: column; gap: 0.4rem; } |
222 | | - } |
223 | | -</style> |
| 269 | + tools.forEach((tool) => { |
| 270 | + const node = document.querySelector<HTMLElement>(`.node-tool[data-tool="${tool}"]`); |
| 271 | + const item = document.querySelector<HTMLElement>(`.eco-item[data-tool="${tool}"]`); |
| 272 | + if (!node || !item) return; |
| 273 | + |
| 274 | + const activate = () => { node.classList.add('active'); item.classList.add('active'); }; |
| 275 | + const deactivate = () => { node.classList.remove('active'); item.classList.remove('active'); }; |
| 276 | + |
| 277 | + node.addEventListener('mouseenter', activate); |
| 278 | + node.addEventListener('mouseleave', deactivate); |
| 279 | + item.addEventListener('mouseenter', activate); |
| 280 | + item.addEventListener('mouseleave', deactivate); |
| 281 | + }); |
| 282 | +</script> |
0 commit comments