@hustle-together/api-dev-tools 1.3.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -3
- package/commands/api-research.md +77 -0
- package/demo/workflow-demo.html +1945 -0
- package/hooks/api-workflow-check.py +135 -26
- package/hooks/enforce-external-research.py +318 -0
- package/hooks/enforce-interview.py +183 -0
- package/hooks/track-tool-use.py +108 -5
- package/hooks/verify-implementation.py +225 -0
- package/package.json +2 -1
- package/templates/api-dev-state.json +3 -1
- package/templates/settings.json +35 -1
|
@@ -0,0 +1,1945 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>API Dev Tools - Interactive Workflow Demo</title>
|
|
7
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
|
|
8
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/ScrollTrigger.min.js"></script>
|
|
9
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/TextPlugin.min.js"></script>
|
|
10
|
+
<style>
|
|
11
|
+
/* ============================================
|
|
12
|
+
90s RETRO TERMINAL AESTHETIC
|
|
13
|
+
Black & White, Monospace, Dashed Borders
|
|
14
|
+
============================================ */
|
|
15
|
+
|
|
16
|
+
* {
|
|
17
|
+
margin: 0;
|
|
18
|
+
padding: 0;
|
|
19
|
+
box-sizing: border-box;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
:root {
|
|
23
|
+
--white: #e0e0e0;
|
|
24
|
+
--grey: #888;
|
|
25
|
+
--dark-grey: #444;
|
|
26
|
+
--black: #0a0a0a;
|
|
27
|
+
--glow: rgba(255, 255, 255, 0.3);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
body {
|
|
31
|
+
background: var(--black);
|
|
32
|
+
color: var(--white);
|
|
33
|
+
font-family: 'Courier New', Courier, monospace;
|
|
34
|
+
line-height: 1.7;
|
|
35
|
+
overflow-x: hidden;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* Navigation */
|
|
39
|
+
.nav {
|
|
40
|
+
position: fixed;
|
|
41
|
+
top: 20px;
|
|
42
|
+
right: 20px;
|
|
43
|
+
z-index: 1000;
|
|
44
|
+
display: flex;
|
|
45
|
+
gap: 10px;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.nav-btn {
|
|
49
|
+
background: transparent;
|
|
50
|
+
border: 1px dashed var(--grey);
|
|
51
|
+
color: var(--white);
|
|
52
|
+
padding: 8px 16px;
|
|
53
|
+
font-family: inherit;
|
|
54
|
+
cursor: pointer;
|
|
55
|
+
transition: all 0.3s;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.nav-btn:hover {
|
|
59
|
+
background: var(--white);
|
|
60
|
+
color: var(--black);
|
|
61
|
+
box-shadow: 0 0 15px var(--glow);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* Progress indicator */
|
|
65
|
+
.progress-bar {
|
|
66
|
+
position: fixed;
|
|
67
|
+
top: 0;
|
|
68
|
+
left: 0;
|
|
69
|
+
height: 3px;
|
|
70
|
+
background: var(--white);
|
|
71
|
+
width: 0%;
|
|
72
|
+
z-index: 1001;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* Section base */
|
|
76
|
+
section {
|
|
77
|
+
min-height: 100vh;
|
|
78
|
+
display: flex;
|
|
79
|
+
flex-direction: column;
|
|
80
|
+
justify-content: center;
|
|
81
|
+
align-items: center;
|
|
82
|
+
padding: 80px 40px;
|
|
83
|
+
position: relative;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* ASCII border decoration */
|
|
87
|
+
.ascii-border {
|
|
88
|
+
border: 1px dashed var(--grey);
|
|
89
|
+
padding: 50px;
|
|
90
|
+
position: relative;
|
|
91
|
+
max-width: 1000px;
|
|
92
|
+
width: 100%;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.ascii-border::before {
|
|
96
|
+
content: '+';
|
|
97
|
+
position: absolute;
|
|
98
|
+
top: -8px;
|
|
99
|
+
left: -8px;
|
|
100
|
+
color: var(--grey);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.ascii-border::after {
|
|
104
|
+
content: '+';
|
|
105
|
+
position: absolute;
|
|
106
|
+
bottom: -8px;
|
|
107
|
+
right: -8px;
|
|
108
|
+
color: var(--grey);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* Typography */
|
|
112
|
+
h1 {
|
|
113
|
+
font-size: 2.5rem;
|
|
114
|
+
font-weight: normal;
|
|
115
|
+
letter-spacing: 4px;
|
|
116
|
+
margin-bottom: 20px;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
h2 {
|
|
120
|
+
font-size: 1.8rem;
|
|
121
|
+
font-weight: normal;
|
|
122
|
+
letter-spacing: 2px;
|
|
123
|
+
margin-bottom: 10px;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
h3 {
|
|
127
|
+
font-size: 1.2rem;
|
|
128
|
+
margin-bottom: 15px;
|
|
129
|
+
text-transform: uppercase;
|
|
130
|
+
letter-spacing: 1px;
|
|
131
|
+
color: var(--grey);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/* Explanation blocks - THE KEY EDUCATIONAL ELEMENT */
|
|
135
|
+
.explanation {
|
|
136
|
+
background: rgba(255, 255, 255, 0.03);
|
|
137
|
+
border-left: 3px solid var(--grey);
|
|
138
|
+
padding: 25px 30px;
|
|
139
|
+
margin: 30px 0;
|
|
140
|
+
font-size: 1rem;
|
|
141
|
+
line-height: 1.9;
|
|
142
|
+
opacity: 0;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.explanation-title {
|
|
146
|
+
font-size: 0.85rem;
|
|
147
|
+
text-transform: uppercase;
|
|
148
|
+
letter-spacing: 3px;
|
|
149
|
+
color: var(--grey);
|
|
150
|
+
margin-bottom: 15px;
|
|
151
|
+
display: flex;
|
|
152
|
+
align-items: center;
|
|
153
|
+
gap: 10px;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.explanation-title::before {
|
|
157
|
+
content: '?';
|
|
158
|
+
width: 24px;
|
|
159
|
+
height: 24px;
|
|
160
|
+
border: 1px dashed var(--grey);
|
|
161
|
+
display: flex;
|
|
162
|
+
align-items: center;
|
|
163
|
+
justify-content: center;
|
|
164
|
+
font-size: 0.9rem;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.explanation p {
|
|
168
|
+
margin-bottom: 15px;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.explanation p:last-child {
|
|
172
|
+
margin-bottom: 0;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.explanation strong {
|
|
176
|
+
color: var(--white);
|
|
177
|
+
font-weight: normal;
|
|
178
|
+
border-bottom: 1px dashed var(--grey);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/* Real example callout */
|
|
182
|
+
.real-example {
|
|
183
|
+
background: rgba(255, 255, 255, 0.05);
|
|
184
|
+
border: 1px dashed var(--white);
|
|
185
|
+
padding: 20px 25px;
|
|
186
|
+
margin: 20px 0;
|
|
187
|
+
position: relative;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.real-example::before {
|
|
191
|
+
content: 'REAL EXAMPLE';
|
|
192
|
+
position: absolute;
|
|
193
|
+
top: -10px;
|
|
194
|
+
left: 20px;
|
|
195
|
+
background: var(--black);
|
|
196
|
+
padding: 0 10px;
|
|
197
|
+
font-size: 0.75rem;
|
|
198
|
+
letter-spacing: 2px;
|
|
199
|
+
color: var(--grey);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.real-example-content {
|
|
203
|
+
font-size: 0.95rem;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/* Cursor blink */
|
|
207
|
+
.cursor {
|
|
208
|
+
display: inline-block;
|
|
209
|
+
width: 10px;
|
|
210
|
+
height: 20px;
|
|
211
|
+
background: var(--white);
|
|
212
|
+
animation: blink 1s infinite;
|
|
213
|
+
vertical-align: middle;
|
|
214
|
+
margin-left: 5px;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
@keyframes blink {
|
|
218
|
+
0%, 50% { opacity: 1; }
|
|
219
|
+
51%, 100% { opacity: 0; }
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/* Step numbers */
|
|
223
|
+
.step-number {
|
|
224
|
+
display: inline-flex;
|
|
225
|
+
align-items: center;
|
|
226
|
+
justify-content: center;
|
|
227
|
+
width: 50px;
|
|
228
|
+
height: 50px;
|
|
229
|
+
border: 2px solid var(--white);
|
|
230
|
+
font-size: 1.5rem;
|
|
231
|
+
margin-right: 20px;
|
|
232
|
+
flex-shrink: 0;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.step-header {
|
|
236
|
+
display: flex;
|
|
237
|
+
align-items: center;
|
|
238
|
+
margin-bottom: 20px;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/* ============================================
|
|
242
|
+
SECTION 1: TITLE
|
|
243
|
+
============================================ */
|
|
244
|
+
#title {
|
|
245
|
+
text-align: center;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
#title h1 {
|
|
249
|
+
font-size: 1.2rem;
|
|
250
|
+
letter-spacing: 3px;
|
|
251
|
+
opacity: 0;
|
|
252
|
+
color: var(--grey);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
#title .package-name {
|
|
256
|
+
font-size: 2.2rem;
|
|
257
|
+
margin: 25px 0;
|
|
258
|
+
opacity: 0;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
#title .version {
|
|
262
|
+
color: var(--grey);
|
|
263
|
+
font-size: 0.9rem;
|
|
264
|
+
opacity: 0;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.tagline {
|
|
268
|
+
color: var(--grey);
|
|
269
|
+
font-style: italic;
|
|
270
|
+
margin-top: 15px;
|
|
271
|
+
font-size: 1.1rem;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.intro-text {
|
|
275
|
+
max-width: 700px;
|
|
276
|
+
margin: 40px auto 0;
|
|
277
|
+
text-align: left;
|
|
278
|
+
font-size: 1rem;
|
|
279
|
+
line-height: 1.9;
|
|
280
|
+
opacity: 0;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.scroll-hint {
|
|
284
|
+
margin-top: 50px;
|
|
285
|
+
color: var(--grey);
|
|
286
|
+
font-size: 0.85rem;
|
|
287
|
+
opacity: 0;
|
|
288
|
+
animation: bounce 2s infinite;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
@keyframes bounce {
|
|
292
|
+
0%, 100% { transform: translateY(0); }
|
|
293
|
+
50% { transform: translateY(10px); }
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/* ============================================
|
|
297
|
+
SECTION 2: THE PROBLEM - GAPS
|
|
298
|
+
============================================ */
|
|
299
|
+
.gap-list {
|
|
300
|
+
list-style: none;
|
|
301
|
+
width: 100%;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.gap-item {
|
|
305
|
+
border: 1px dashed var(--dark-grey);
|
|
306
|
+
padding: 25px 30px;
|
|
307
|
+
margin-bottom: 20px;
|
|
308
|
+
opacity: 0;
|
|
309
|
+
transform: translateX(-30px);
|
|
310
|
+
transition: all 0.3s;
|
|
311
|
+
position: relative;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.gap-item:hover {
|
|
315
|
+
border-color: var(--white);
|
|
316
|
+
box-shadow: 0 0 25px rgba(255,255,255,0.1);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.gap-item::before {
|
|
320
|
+
content: 'X';
|
|
321
|
+
position: absolute;
|
|
322
|
+
left: -35px;
|
|
323
|
+
top: 50%;
|
|
324
|
+
transform: translateY(-50%);
|
|
325
|
+
color: var(--grey);
|
|
326
|
+
font-size: 1.2rem;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.gap-number {
|
|
330
|
+
color: var(--grey);
|
|
331
|
+
font-size: 0.8rem;
|
|
332
|
+
text-transform: uppercase;
|
|
333
|
+
letter-spacing: 2px;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.gap-title {
|
|
337
|
+
font-size: 1.15rem;
|
|
338
|
+
margin: 8px 0;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.gap-desc {
|
|
342
|
+
color: var(--grey);
|
|
343
|
+
font-size: 0.95rem;
|
|
344
|
+
margin-bottom: 10px;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.gap-example {
|
|
348
|
+
font-size: 0.85rem;
|
|
349
|
+
padding: 12px 15px;
|
|
350
|
+
background: rgba(255,255,255,0.03);
|
|
351
|
+
border-left: 2px solid var(--dark-grey);
|
|
352
|
+
margin-top: 10px;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.gap-example .bad {
|
|
356
|
+
color: var(--grey);
|
|
357
|
+
text-decoration: line-through;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.gap-example .good {
|
|
361
|
+
color: var(--white);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/* ============================================
|
|
365
|
+
SECTION 3: SOLUTION OVERVIEW
|
|
366
|
+
============================================ */
|
|
367
|
+
.solution-grid {
|
|
368
|
+
display: grid;
|
|
369
|
+
grid-template-columns: repeat(3, 1fr);
|
|
370
|
+
gap: 25px;
|
|
371
|
+
margin-top: 30px;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.solution-card {
|
|
375
|
+
border: 1px dashed var(--dark-grey);
|
|
376
|
+
padding: 30px 25px;
|
|
377
|
+
text-align: center;
|
|
378
|
+
opacity: 0;
|
|
379
|
+
transform: translateY(20px);
|
|
380
|
+
transition: all 0.3s;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.solution-card:hover {
|
|
384
|
+
border-color: var(--white);
|
|
385
|
+
box-shadow: 0 0 25px rgba(255,255,255,0.1);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
.solution-icon {
|
|
389
|
+
font-size: 2rem;
|
|
390
|
+
margin-bottom: 15px;
|
|
391
|
+
display: block;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
.solution-title {
|
|
395
|
+
font-size: 1rem;
|
|
396
|
+
margin-bottom: 10px;
|
|
397
|
+
text-transform: uppercase;
|
|
398
|
+
letter-spacing: 1px;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.solution-desc {
|
|
402
|
+
font-size: 0.85rem;
|
|
403
|
+
color: var(--grey);
|
|
404
|
+
line-height: 1.6;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/* ============================================
|
|
408
|
+
SECTION 4: HOOK SYSTEM
|
|
409
|
+
============================================ */
|
|
410
|
+
.hook-diagram {
|
|
411
|
+
width: 100%;
|
|
412
|
+
font-size: 0.9rem;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.flow-box {
|
|
416
|
+
border: 1px dashed var(--grey);
|
|
417
|
+
padding: 18px 30px;
|
|
418
|
+
margin: 12px 0;
|
|
419
|
+
text-align: center;
|
|
420
|
+
opacity: 0;
|
|
421
|
+
transition: all 0.3s;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.flow-box:hover {
|
|
425
|
+
background: rgba(255,255,255,0.05);
|
|
426
|
+
box-shadow: 0 0 20px var(--glow);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.flow-arrow {
|
|
430
|
+
text-align: center;
|
|
431
|
+
color: var(--grey);
|
|
432
|
+
font-size: 1.5rem;
|
|
433
|
+
opacity: 0;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.hook-group {
|
|
437
|
+
border: 2px dashed var(--white);
|
|
438
|
+
padding: 25px;
|
|
439
|
+
margin: 25px 0;
|
|
440
|
+
opacity: 0;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
.hook-group h4 {
|
|
444
|
+
color: var(--grey);
|
|
445
|
+
font-size: 0.85rem;
|
|
446
|
+
text-transform: uppercase;
|
|
447
|
+
letter-spacing: 2px;
|
|
448
|
+
margin-bottom: 15px;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
.hook-file {
|
|
452
|
+
padding: 12px 20px;
|
|
453
|
+
margin: 8px 0;
|
|
454
|
+
border-left: 2px solid var(--grey);
|
|
455
|
+
font-size: 0.9rem;
|
|
456
|
+
opacity: 0;
|
|
457
|
+
transition: all 0.3s;
|
|
458
|
+
display: flex;
|
|
459
|
+
justify-content: space-between;
|
|
460
|
+
align-items: center;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
.hook-file:hover {
|
|
464
|
+
border-left-color: var(--white);
|
|
465
|
+
background: rgba(255,255,255,0.05);
|
|
466
|
+
padding-left: 25px;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
.hook-file code {
|
|
470
|
+
color: var(--white);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
.hook-purpose {
|
|
474
|
+
color: var(--grey);
|
|
475
|
+
font-size: 0.8rem;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.result-box {
|
|
479
|
+
display: flex;
|
|
480
|
+
gap: 40px;
|
|
481
|
+
justify-content: center;
|
|
482
|
+
margin-top: 25px;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
.result-allowed, .result-blocked {
|
|
486
|
+
padding: 18px 35px;
|
|
487
|
+
border: 2px solid;
|
|
488
|
+
opacity: 0;
|
|
489
|
+
transition: all 0.3s;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
.result-allowed {
|
|
493
|
+
border-color: var(--grey);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
.result-blocked {
|
|
497
|
+
border-color: var(--white);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
.result-allowed:hover, .result-blocked:hover {
|
|
501
|
+
transform: scale(1.05);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/* ============================================
|
|
505
|
+
SECTION 5: 10-PHASE WORKFLOW
|
|
506
|
+
============================================ */
|
|
507
|
+
.phase-grid {
|
|
508
|
+
display: grid;
|
|
509
|
+
grid-template-columns: repeat(5, 1fr);
|
|
510
|
+
gap: 18px;
|
|
511
|
+
width: 100%;
|
|
512
|
+
margin-top: 30px;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
.phase-box {
|
|
516
|
+
border: 1px dashed var(--dark-grey);
|
|
517
|
+
padding: 25px 15px;
|
|
518
|
+
text-align: center;
|
|
519
|
+
opacity: 0;
|
|
520
|
+
transform: scale(0.9);
|
|
521
|
+
transition: all 0.3s;
|
|
522
|
+
position: relative;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
.phase-box:hover {
|
|
526
|
+
border-color: var(--white);
|
|
527
|
+
box-shadow: 0 0 25px rgba(255,255,255,0.15);
|
|
528
|
+
transform: scale(1.02);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
.phase-box.active {
|
|
532
|
+
border-color: var(--white);
|
|
533
|
+
background: rgba(255,255,255,0.05);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
.phase-number {
|
|
537
|
+
font-size: 2.2rem;
|
|
538
|
+
color: var(--dark-grey);
|
|
539
|
+
margin-bottom: 10px;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
.phase-box.active .phase-number {
|
|
543
|
+
color: var(--white);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
.phase-name {
|
|
547
|
+
font-size: 0.75rem;
|
|
548
|
+
text-transform: uppercase;
|
|
549
|
+
letter-spacing: 1px;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
.phase-status {
|
|
553
|
+
position: absolute;
|
|
554
|
+
top: 8px;
|
|
555
|
+
right: 8px;
|
|
556
|
+
font-size: 0.7rem;
|
|
557
|
+
color: var(--grey);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
.phase-connector {
|
|
561
|
+
grid-column: span 5;
|
|
562
|
+
text-align: center;
|
|
563
|
+
color: var(--grey);
|
|
564
|
+
font-size: 0.8rem;
|
|
565
|
+
opacity: 0;
|
|
566
|
+
padding: 10px 0;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
.phase-desc {
|
|
570
|
+
font-size: 0.7rem;
|
|
571
|
+
color: var(--grey);
|
|
572
|
+
margin-top: 8px;
|
|
573
|
+
line-height: 1.4;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/* ============================================
|
|
577
|
+
SECTION 6: REAL WALKTHROUGH
|
|
578
|
+
============================================ */
|
|
579
|
+
.walkthrough-step {
|
|
580
|
+
border: 1px dashed var(--dark-grey);
|
|
581
|
+
padding: 30px;
|
|
582
|
+
margin-bottom: 25px;
|
|
583
|
+
opacity: 0;
|
|
584
|
+
transform: translateY(20px);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
.walkthrough-step.active {
|
|
588
|
+
border-color: var(--white);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
.walkthrough-header {
|
|
592
|
+
display: flex;
|
|
593
|
+
align-items: center;
|
|
594
|
+
gap: 20px;
|
|
595
|
+
margin-bottom: 20px;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
.walkthrough-num {
|
|
599
|
+
width: 45px;
|
|
600
|
+
height: 45px;
|
|
601
|
+
border: 2px solid var(--white);
|
|
602
|
+
display: flex;
|
|
603
|
+
align-items: center;
|
|
604
|
+
justify-content: center;
|
|
605
|
+
font-size: 1.3rem;
|
|
606
|
+
flex-shrink: 0;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
.walkthrough-title {
|
|
610
|
+
font-size: 1.1rem;
|
|
611
|
+
text-transform: uppercase;
|
|
612
|
+
letter-spacing: 1px;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
.walkthrough-content {
|
|
616
|
+
padding-left: 65px;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
.walkthrough-desc {
|
|
620
|
+
color: var(--grey);
|
|
621
|
+
margin-bottom: 15px;
|
|
622
|
+
line-height: 1.8;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
.walkthrough-example {
|
|
626
|
+
background: #111;
|
|
627
|
+
padding: 15px 20px;
|
|
628
|
+
font-size: 0.85rem;
|
|
629
|
+
border-left: 3px solid var(--grey);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
.walkthrough-example .label {
|
|
633
|
+
color: var(--grey);
|
|
634
|
+
font-size: 0.75rem;
|
|
635
|
+
text-transform: uppercase;
|
|
636
|
+
letter-spacing: 1px;
|
|
637
|
+
margin-bottom: 8px;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/* ============================================
|
|
641
|
+
SECTION 7: LIVE DEMO TERMINAL
|
|
642
|
+
============================================ */
|
|
643
|
+
.terminal {
|
|
644
|
+
background: #0d0d0d;
|
|
645
|
+
border: 1px solid var(--grey);
|
|
646
|
+
padding: 25px;
|
|
647
|
+
width: 100%;
|
|
648
|
+
font-size: 0.85rem;
|
|
649
|
+
position: relative;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
.terminal-header {
|
|
653
|
+
display: flex;
|
|
654
|
+
gap: 8px;
|
|
655
|
+
margin-bottom: 20px;
|
|
656
|
+
padding-bottom: 15px;
|
|
657
|
+
border-bottom: 1px dashed var(--dark-grey);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
.terminal-dot {
|
|
661
|
+
width: 12px;
|
|
662
|
+
height: 12px;
|
|
663
|
+
border-radius: 50%;
|
|
664
|
+
border: 1px solid var(--grey);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
.terminal-title {
|
|
668
|
+
margin-left: auto;
|
|
669
|
+
color: var(--grey);
|
|
670
|
+
font-size: 0.8rem;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
.terminal-line {
|
|
674
|
+
padding: 8px 0;
|
|
675
|
+
opacity: 0;
|
|
676
|
+
display: flex;
|
|
677
|
+
align-items: flex-start;
|
|
678
|
+
gap: 12px;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
.terminal-prompt {
|
|
682
|
+
color: var(--grey);
|
|
683
|
+
flex-shrink: 0;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
.terminal-command {
|
|
687
|
+
color: var(--white);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
.terminal-result {
|
|
691
|
+
padding-left: 25px;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
.terminal-blocked {
|
|
695
|
+
color: var(--white);
|
|
696
|
+
border-left: 3px solid var(--white);
|
|
697
|
+
padding-left: 15px;
|
|
698
|
+
background: rgba(255,255,255,0.03);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
.terminal-allowed {
|
|
702
|
+
color: var(--grey);
|
|
703
|
+
border-left: 3px solid var(--grey);
|
|
704
|
+
padding-left: 15px;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
.terminal-logged {
|
|
708
|
+
color: var(--grey);
|
|
709
|
+
font-style: italic;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
.terminal-comment {
|
|
713
|
+
color: var(--dark-grey);
|
|
714
|
+
font-size: 0.8rem;
|
|
715
|
+
padding-left: 25px;
|
|
716
|
+
margin-bottom: 5px;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
/* ============================================
|
|
720
|
+
SECTION 8: STATE FILE
|
|
721
|
+
============================================ */
|
|
722
|
+
.json-viewer {
|
|
723
|
+
background: #0d0d0d;
|
|
724
|
+
border: 1px solid var(--grey);
|
|
725
|
+
padding: 25px;
|
|
726
|
+
font-size: 0.85rem;
|
|
727
|
+
width: 100%;
|
|
728
|
+
overflow-x: auto;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
.json-key {
|
|
732
|
+
color: var(--grey);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
.json-value {
|
|
736
|
+
color: var(--white);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
.json-string {
|
|
740
|
+
color: var(--grey);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
.json-line {
|
|
744
|
+
opacity: 0;
|
|
745
|
+
padding: 3px 0;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
.json-line.highlight {
|
|
749
|
+
background: rgba(255,255,255,0.08);
|
|
750
|
+
margin: 0 -25px;
|
|
751
|
+
padding-left: 25px;
|
|
752
|
+
padding-right: 25px;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
.json-comment {
|
|
756
|
+
color: var(--dark-grey);
|
|
757
|
+
font-size: 0.75rem;
|
|
758
|
+
margin-left: 20px;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
/* ============================================
|
|
762
|
+
SECTION 9: INSTALLATION
|
|
763
|
+
============================================ */
|
|
764
|
+
.install-command {
|
|
765
|
+
background: #0d0d0d;
|
|
766
|
+
border: 1px solid var(--grey);
|
|
767
|
+
padding: 20px 30px;
|
|
768
|
+
font-size: 1.1rem;
|
|
769
|
+
margin: 30px 0;
|
|
770
|
+
text-align: center;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
.install-command code {
|
|
774
|
+
color: var(--white);
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
.install-flow {
|
|
778
|
+
width: 100%;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
.install-step {
|
|
782
|
+
display: flex;
|
|
783
|
+
align-items: center;
|
|
784
|
+
gap: 25px;
|
|
785
|
+
padding: 20px 0;
|
|
786
|
+
border-bottom: 1px dashed var(--dark-grey);
|
|
787
|
+
opacity: 0;
|
|
788
|
+
transform: translateY(20px);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
.install-step:last-child {
|
|
792
|
+
border-bottom: none;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
.install-icon {
|
|
796
|
+
width: 50px;
|
|
797
|
+
height: 50px;
|
|
798
|
+
border: 1px dashed var(--grey);
|
|
799
|
+
display: flex;
|
|
800
|
+
align-items: center;
|
|
801
|
+
justify-content: center;
|
|
802
|
+
flex-shrink: 0;
|
|
803
|
+
font-size: 1.2rem;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
.install-content {
|
|
807
|
+
flex: 1;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
.install-from {
|
|
811
|
+
color: var(--grey);
|
|
812
|
+
font-size: 0.9rem;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
.install-arrow {
|
|
816
|
+
color: var(--grey);
|
|
817
|
+
flex-shrink: 0;
|
|
818
|
+
font-size: 1.2rem;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
.install-to {
|
|
822
|
+
color: var(--white);
|
|
823
|
+
font-size: 0.95rem;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
.install-note {
|
|
827
|
+
color: var(--grey);
|
|
828
|
+
font-size: 0.8rem;
|
|
829
|
+
margin-top: 5px;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
/* ============================================
|
|
833
|
+
SECTION 10: CREDITS
|
|
834
|
+
============================================ */
|
|
835
|
+
#credits {
|
|
836
|
+
text-align: center;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
.credit-links {
|
|
840
|
+
display: flex;
|
|
841
|
+
gap: 30px;
|
|
842
|
+
margin-top: 40px;
|
|
843
|
+
flex-wrap: wrap;
|
|
844
|
+
justify-content: center;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
.credit-link {
|
|
848
|
+
border: 1px dashed var(--grey);
|
|
849
|
+
padding: 18px 35px;
|
|
850
|
+
text-decoration: none;
|
|
851
|
+
color: var(--white);
|
|
852
|
+
transition: all 0.3s;
|
|
853
|
+
opacity: 0;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
.credit-link:hover {
|
|
857
|
+
background: var(--white);
|
|
858
|
+
color: var(--black);
|
|
859
|
+
box-shadow: 0 0 25px var(--glow);
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
.made-with {
|
|
863
|
+
margin-top: 50px;
|
|
864
|
+
color: var(--grey);
|
|
865
|
+
font-size: 0.95rem;
|
|
866
|
+
opacity: 0;
|
|
867
|
+
line-height: 1.8;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
/* ============================================
|
|
871
|
+
SECTION INDICATORS
|
|
872
|
+
============================================ */
|
|
873
|
+
.section-indicator {
|
|
874
|
+
position: fixed;
|
|
875
|
+
right: 25px;
|
|
876
|
+
top: 50%;
|
|
877
|
+
transform: translateY(-50%);
|
|
878
|
+
display: flex;
|
|
879
|
+
flex-direction: column;
|
|
880
|
+
gap: 12px;
|
|
881
|
+
z-index: 1000;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
.section-dot {
|
|
885
|
+
width: 10px;
|
|
886
|
+
height: 10px;
|
|
887
|
+
border: 1px solid var(--grey);
|
|
888
|
+
border-radius: 50%;
|
|
889
|
+
cursor: pointer;
|
|
890
|
+
transition: all 0.3s;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
.section-dot:hover,
|
|
894
|
+
.section-dot.active {
|
|
895
|
+
background: var(--white);
|
|
896
|
+
box-shadow: 0 0 12px var(--glow);
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
/* ============================================
|
|
900
|
+
RESPONSIVE
|
|
901
|
+
============================================ */
|
|
902
|
+
@media (max-width: 900px) {
|
|
903
|
+
.phase-grid {
|
|
904
|
+
grid-template-columns: repeat(2, 1fr);
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
.phase-connector {
|
|
908
|
+
grid-column: span 2;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
.solution-grid {
|
|
912
|
+
grid-template-columns: 1fr;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
h1 {
|
|
916
|
+
font-size: 1.8rem;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
.ascii-border {
|
|
920
|
+
padding: 30px 20px;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
.result-box {
|
|
924
|
+
flex-direction: column;
|
|
925
|
+
align-items: center;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
.walkthrough-content {
|
|
929
|
+
padding-left: 0;
|
|
930
|
+
margin-top: 15px;
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
.install-step {
|
|
934
|
+
flex-wrap: wrap;
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
</style>
|
|
938
|
+
</head>
|
|
939
|
+
<body>
|
|
940
|
+
|
|
941
|
+
<!-- Progress Bar -->
|
|
942
|
+
<div class="progress-bar" id="progressBar"></div>
|
|
943
|
+
|
|
944
|
+
<!-- Navigation -->
|
|
945
|
+
<nav class="nav">
|
|
946
|
+
<button class="nav-btn" id="playBtn">AUTO PLAY</button>
|
|
947
|
+
<button class="nav-btn" id="resetBtn">RESTART</button>
|
|
948
|
+
</nav>
|
|
949
|
+
|
|
950
|
+
<!-- Section Indicators -->
|
|
951
|
+
<div class="section-indicator" id="sectionIndicator"></div>
|
|
952
|
+
|
|
953
|
+
<!-- ============================================
|
|
954
|
+
SECTION 1: WELCOME & INTRODUCTION
|
|
955
|
+
============================================ -->
|
|
956
|
+
<section id="intro">
|
|
957
|
+
<div class="ascii-border">
|
|
958
|
+
<h1 id="titleText">INTERVIEW-DRIVEN API DEVELOPMENT</h1>
|
|
959
|
+
<div class="package-name" id="packageName">@hustle-together/api-dev-tools</div>
|
|
960
|
+
<div class="version" id="versionText">v1.6.0</div>
|
|
961
|
+
<p class="tagline">"Interview first, test first, document always"<span class="cursor"></span></p>
|
|
962
|
+
|
|
963
|
+
<div class="intro-text">
|
|
964
|
+
<p>
|
|
965
|
+
This tool helps you build APIs the right way by <strong>enforcing a structured workflow</strong>.
|
|
966
|
+
Instead of letting AI assistants jump straight to code, it ensures they first understand
|
|
967
|
+
what you actually want, research the right libraries, and follow test-driven development.
|
|
968
|
+
</p>
|
|
969
|
+
<p style="margin-top: 20px;">
|
|
970
|
+
<strong>Scroll down</strong> to see how it works, step by step, using a real example:
|
|
971
|
+
building an AI chat API with the Vercel AI SDK.
|
|
972
|
+
</p>
|
|
973
|
+
</div>
|
|
974
|
+
|
|
975
|
+
<div class="scroll-hint">[ SCROLL TO BEGIN ]</div>
|
|
976
|
+
</div>
|
|
977
|
+
</section>
|
|
978
|
+
|
|
979
|
+
<!-- ============================================
|
|
980
|
+
SECTION 2: THE PROBLEM - WHAT GOES WRONG
|
|
981
|
+
============================================ -->
|
|
982
|
+
<section id="problems">
|
|
983
|
+
<div class="ascii-border">
|
|
984
|
+
<h2>THE PROBLEM</h2>
|
|
985
|
+
<h3>What Goes Wrong Without Structure</h3>
|
|
986
|
+
|
|
987
|
+
<div class="explanation">
|
|
988
|
+
<div class="explanation-title">Why This Matters</div>
|
|
989
|
+
<p>
|
|
990
|
+
When you ask an AI assistant to build an API, it often <strong>skips important steps</strong>.
|
|
991
|
+
It might use outdated information from its training data, make assumptions about what you want,
|
|
992
|
+
or claim tasks are complete without actually verifying them.
|
|
993
|
+
</p>
|
|
994
|
+
<p>
|
|
995
|
+
These are the <strong>5 most common gaps</strong> we've identified - and the problems they cause:
|
|
996
|
+
</p>
|
|
997
|
+
</div>
|
|
998
|
+
|
|
999
|
+
<ul class="gap-list">
|
|
1000
|
+
<li class="gap-item">
|
|
1001
|
+
<span class="gap-number">Gap 01</span>
|
|
1002
|
+
<div class="gap-title">AI Doesn't Use Your Exact Words</div>
|
|
1003
|
+
<div class="gap-desc">You say one thing, but the AI searches for something different.</div>
|
|
1004
|
+
<div class="gap-example">
|
|
1005
|
+
<span class="bad">You: "Use Vercel AI Gateway"</span><br>
|
|
1006
|
+
<span class="bad">AI searches: "Vercel AI SDK" (wrong!)</span><br>
|
|
1007
|
+
<span class="good">Should search: "Vercel AI Gateway" (your exact words)</span>
|
|
1008
|
+
</div>
|
|
1009
|
+
</li>
|
|
1010
|
+
<li class="gap-item">
|
|
1011
|
+
<span class="gap-number">Gap 02</span>
|
|
1012
|
+
<div class="gap-title">No Proof Files Were Actually Changed</div>
|
|
1013
|
+
<div class="gap-desc">AI says "I updated all the files" but never runs git diff to prove it.</div>
|
|
1014
|
+
<div class="gap-example">
|
|
1015
|
+
AI: "Migration complete! All 6 files updated."<br>
|
|
1016
|
+
Reality: Only 4 files were changed, 2 were missed.
|
|
1017
|
+
</div>
|
|
1018
|
+
</li>
|
|
1019
|
+
<li class="gap-item">
|
|
1020
|
+
<span class="gap-number">Gap 03</span>
|
|
1021
|
+
<div class="gap-title">Skipped Tests Go Uninvestigated</div>
|
|
1022
|
+
<div class="gap-desc">AI sees "9 tests skipped" and says "that's expected" without checking why.</div>
|
|
1023
|
+
<div class="gap-example">
|
|
1024
|
+
Tests might be skipping because they check the wrong environment variables.
|
|
1025
|
+
</div>
|
|
1026
|
+
</li>
|
|
1027
|
+
<li class="gap-item">
|
|
1028
|
+
<span class="gap-number">Gap 04</span>
|
|
1029
|
+
<div class="gap-title">Tasks Marked Done Without Verification</div>
|
|
1030
|
+
<div class="gap-desc">AI declares "complete!" without checking if the code matches your requirements.</div>
|
|
1031
|
+
<div class="gap-example">
|
|
1032
|
+
You asked for "single API key" but code still uses 4 separate keys.
|
|
1033
|
+
</div>
|
|
1034
|
+
</li>
|
|
1035
|
+
<li class="gap-item">
|
|
1036
|
+
<span class="gap-number">Gap 05</span>
|
|
1037
|
+
<div class="gap-title">Tests Don't Match Production Code</div>
|
|
1038
|
+
<div class="gap-desc">Production code uses new patterns, but tests still check old patterns.</div>
|
|
1039
|
+
<div class="gap-example">
|
|
1040
|
+
<span class="bad">Production: AI_GATEWAY_API_KEY</span><br>
|
|
1041
|
+
<span class="bad">Tests: OPENAI_API_KEY (outdated!)</span>
|
|
1042
|
+
</div>
|
|
1043
|
+
</li>
|
|
1044
|
+
</ul>
|
|
1045
|
+
</div>
|
|
1046
|
+
</section>
|
|
1047
|
+
|
|
1048
|
+
<!-- ============================================
|
|
1049
|
+
SECTION 3: THE SOLUTION - OVERVIEW
|
|
1050
|
+
============================================ -->
|
|
1051
|
+
<section id="solution">
|
|
1052
|
+
<div class="ascii-border">
|
|
1053
|
+
<h2>THE SOLUTION</h2>
|
|
1054
|
+
<h3>Programmatic Enforcement</h3>
|
|
1055
|
+
|
|
1056
|
+
<div class="explanation">
|
|
1057
|
+
<div class="explanation-title">How We Fix This</div>
|
|
1058
|
+
<p>
|
|
1059
|
+
Instead of just <em>asking</em> the AI to follow a process (which it might ignore),
|
|
1060
|
+
we use <strong>Python hooks</strong> that intercept every action and enforce rules.
|
|
1061
|
+
</p>
|
|
1062
|
+
<p>
|
|
1063
|
+
Think of it like guardrails on a highway. The AI can still drive,
|
|
1064
|
+
but it literally <strong>cannot</strong> skip important steps - the system blocks it.
|
|
1065
|
+
</p>
|
|
1066
|
+
</div>
|
|
1067
|
+
|
|
1068
|
+
<div class="solution-grid">
|
|
1069
|
+
<div class="solution-card">
|
|
1070
|
+
<span class="solution-icon">[R]</span>
|
|
1071
|
+
<div class="solution-title">Research First</div>
|
|
1072
|
+
<div class="solution-desc">
|
|
1073
|
+
AI must search for live documentation before writing any code.
|
|
1074
|
+
No more outdated training data.
|
|
1075
|
+
</div>
|
|
1076
|
+
</div>
|
|
1077
|
+
<div class="solution-card">
|
|
1078
|
+
<span class="solution-icon">[I]</span>
|
|
1079
|
+
<div class="solution-title">Interview Required</div>
|
|
1080
|
+
<div class="solution-desc">
|
|
1081
|
+
AI must ask YOU questions and wait for answers.
|
|
1082
|
+
No more assumptions about what you want.
|
|
1083
|
+
</div>
|
|
1084
|
+
</div>
|
|
1085
|
+
<div class="solution-card">
|
|
1086
|
+
<span class="solution-icon">[V]</span>
|
|
1087
|
+
<div class="solution-title">Verification Built-In</div>
|
|
1088
|
+
<div class="solution-desc">
|
|
1089
|
+
System checks implementation matches interview.
|
|
1090
|
+
Warns about mismatches before completing.
|
|
1091
|
+
</div>
|
|
1092
|
+
</div>
|
|
1093
|
+
</div>
|
|
1094
|
+
</div>
|
|
1095
|
+
</section>
|
|
1096
|
+
|
|
1097
|
+
<!-- ============================================
|
|
1098
|
+
SECTION 4: HOW HOOKS WORK
|
|
1099
|
+
============================================ -->
|
|
1100
|
+
<section id="hooks">
|
|
1101
|
+
<div class="ascii-border">
|
|
1102
|
+
<h2>HOW IT WORKS</h2>
|
|
1103
|
+
<h3>The Hook System</h3>
|
|
1104
|
+
|
|
1105
|
+
<div class="explanation">
|
|
1106
|
+
<div class="explanation-title">What Are Hooks?</div>
|
|
1107
|
+
<p>
|
|
1108
|
+
Hooks are small Python scripts that run <strong>automatically</strong> whenever
|
|
1109
|
+
the AI tries to do something. They check conditions and can either
|
|
1110
|
+
<strong>allow</strong> or <strong>block</strong> the action.
|
|
1111
|
+
</p>
|
|
1112
|
+
<p>
|
|
1113
|
+
There are 3 types: <strong>PreToolUse</strong> (before an action),
|
|
1114
|
+
<strong>PostToolUse</strong> (after an action), and <strong>Stop</strong> (when trying to finish).
|
|
1115
|
+
</p>
|
|
1116
|
+
</div>
|
|
1117
|
+
|
|
1118
|
+
<div class="hook-diagram">
|
|
1119
|
+
<div class="flow-box">YOU: "Build me an AI chat API"</div>
|
|
1120
|
+
<div class="flow-arrow">|</div>
|
|
1121
|
+
<div class="flow-box">AI: Tries to write code</div>
|
|
1122
|
+
<div class="flow-arrow">|</div>
|
|
1123
|
+
|
|
1124
|
+
<div class="hook-group">
|
|
1125
|
+
<h4>PreToolUse Hooks (Before Writing Code)</h4>
|
|
1126
|
+
<div class="hook-file">
|
|
1127
|
+
<code>enforce-research.py</code>
|
|
1128
|
+
<span class="hook-purpose">Must research first</span>
|
|
1129
|
+
</div>
|
|
1130
|
+
<div class="hook-file">
|
|
1131
|
+
<code>enforce-interview.py</code>
|
|
1132
|
+
<span class="hook-purpose">Must ask user questions</span>
|
|
1133
|
+
</div>
|
|
1134
|
+
<div class="hook-file">
|
|
1135
|
+
<code>verify-implementation.py</code>
|
|
1136
|
+
<span class="hook-purpose">Check term matching</span>
|
|
1137
|
+
</div>
|
|
1138
|
+
</div>
|
|
1139
|
+
|
|
1140
|
+
<div class="hook-group">
|
|
1141
|
+
<h4>PostToolUse Hooks (After Actions)</h4>
|
|
1142
|
+
<div class="hook-file">
|
|
1143
|
+
<code>track-tool-use.py</code>
|
|
1144
|
+
<span class="hook-purpose">Log all research activity</span>
|
|
1145
|
+
</div>
|
|
1146
|
+
</div>
|
|
1147
|
+
|
|
1148
|
+
<div class="hook-group">
|
|
1149
|
+
<h4>Stop Hook (When Finishing)</h4>
|
|
1150
|
+
<div class="hook-file">
|
|
1151
|
+
<code>api-workflow-check.py</code>
|
|
1152
|
+
<span class="hook-purpose">Verify all phases done + git diff</span>
|
|
1153
|
+
</div>
|
|
1154
|
+
</div>
|
|
1155
|
+
|
|
1156
|
+
<div class="flow-arrow">|</div>
|
|
1157
|
+
|
|
1158
|
+
<div class="result-box">
|
|
1159
|
+
<div class="result-allowed">[ ALLOWED ]<br><small>All checks pass</small></div>
|
|
1160
|
+
<div class="result-blocked">[ BLOCKED ]<br><small>Missing requirements</small></div>
|
|
1161
|
+
</div>
|
|
1162
|
+
</div>
|
|
1163
|
+
</div>
|
|
1164
|
+
</section>
|
|
1165
|
+
|
|
1166
|
+
<!-- ============================================
|
|
1167
|
+
SECTION 5: THE 10 PHASES
|
|
1168
|
+
============================================ -->
|
|
1169
|
+
<section id="phases">
|
|
1170
|
+
<div class="ascii-border">
|
|
1171
|
+
<h2>THE WORKFLOW</h2>
|
|
1172
|
+
<h3>10 Enforced Phases</h3>
|
|
1173
|
+
|
|
1174
|
+
<div class="explanation">
|
|
1175
|
+
<div class="explanation-title">The Complete Process</div>
|
|
1176
|
+
<p>
|
|
1177
|
+
Every API goes through these 10 phases. The system tracks progress and won't let
|
|
1178
|
+
the AI skip ahead. This ensures <strong>thorough, consistent results</strong> every time.
|
|
1179
|
+
</p>
|
|
1180
|
+
</div>
|
|
1181
|
+
|
|
1182
|
+
<div class="phase-grid">
|
|
1183
|
+
<div class="phase-box" data-phase="1">
|
|
1184
|
+
<div class="phase-status"></div>
|
|
1185
|
+
<div class="phase-number">01</div>
|
|
1186
|
+
<div class="phase-name">Scope</div>
|
|
1187
|
+
<div class="phase-desc">Define what we're building</div>
|
|
1188
|
+
</div>
|
|
1189
|
+
<div class="phase-box" data-phase="2">
|
|
1190
|
+
<div class="phase-status"></div>
|
|
1191
|
+
<div class="phase-number">02</div>
|
|
1192
|
+
<div class="phase-name">Research</div>
|
|
1193
|
+
<div class="phase-desc">Find live documentation</div>
|
|
1194
|
+
</div>
|
|
1195
|
+
<div class="phase-box" data-phase="3">
|
|
1196
|
+
<div class="phase-status"></div>
|
|
1197
|
+
<div class="phase-number">03</div>
|
|
1198
|
+
<div class="phase-name">Interview</div>
|
|
1199
|
+
<div class="phase-desc">Ask user questions</div>
|
|
1200
|
+
</div>
|
|
1201
|
+
<div class="phase-box" data-phase="4">
|
|
1202
|
+
<div class="phase-status"></div>
|
|
1203
|
+
<div class="phase-number">04</div>
|
|
1204
|
+
<div class="phase-name">Deep Research</div>
|
|
1205
|
+
<div class="phase-desc">Based on interview answers</div>
|
|
1206
|
+
</div>
|
|
1207
|
+
<div class="phase-box" data-phase="5">
|
|
1208
|
+
<div class="phase-status"></div>
|
|
1209
|
+
<div class="phase-number">05</div>
|
|
1210
|
+
<div class="phase-name">Schema</div>
|
|
1211
|
+
<div class="phase-desc">Define request/response</div>
|
|
1212
|
+
</div>
|
|
1213
|
+
|
|
1214
|
+
<div class="phase-connector">- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -</div>
|
|
1215
|
+
|
|
1216
|
+
<div class="phase-box" data-phase="6">
|
|
1217
|
+
<div class="phase-status"></div>
|
|
1218
|
+
<div class="phase-number">06</div>
|
|
1219
|
+
<div class="phase-name">Environment</div>
|
|
1220
|
+
<div class="phase-desc">Check API keys exist</div>
|
|
1221
|
+
</div>
|
|
1222
|
+
<div class="phase-box" data-phase="7">
|
|
1223
|
+
<div class="phase-status"></div>
|
|
1224
|
+
<div class="phase-number">07</div>
|
|
1225
|
+
<div class="phase-name">TDD Red</div>
|
|
1226
|
+
<div class="phase-desc">Write failing tests</div>
|
|
1227
|
+
</div>
|
|
1228
|
+
<div class="phase-box" data-phase="8">
|
|
1229
|
+
<div class="phase-status"></div>
|
|
1230
|
+
<div class="phase-number">08</div>
|
|
1231
|
+
<div class="phase-name">TDD Green</div>
|
|
1232
|
+
<div class="phase-desc">Make tests pass</div>
|
|
1233
|
+
</div>
|
|
1234
|
+
<div class="phase-box" data-phase="9">
|
|
1235
|
+
<div class="phase-status"></div>
|
|
1236
|
+
<div class="phase-number">09</div>
|
|
1237
|
+
<div class="phase-name">Refactor</div>
|
|
1238
|
+
<div class="phase-desc">Clean up the code</div>
|
|
1239
|
+
</div>
|
|
1240
|
+
<div class="phase-box" data-phase="10">
|
|
1241
|
+
<div class="phase-status"></div>
|
|
1242
|
+
<div class="phase-number">10</div>
|
|
1243
|
+
<div class="phase-name">Documentation</div>
|
|
1244
|
+
<div class="phase-desc">Update all docs</div>
|
|
1245
|
+
</div>
|
|
1246
|
+
</div>
|
|
1247
|
+
</div>
|
|
1248
|
+
</section>
|
|
1249
|
+
|
|
1250
|
+
<!-- ============================================
|
|
1251
|
+
SECTION 6: REAL EXAMPLE WALKTHROUGH
|
|
1252
|
+
============================================ -->
|
|
1253
|
+
<section id="walkthrough">
|
|
1254
|
+
<div class="ascii-border">
|
|
1255
|
+
<h2>REAL EXAMPLE</h2>
|
|
1256
|
+
<h3>Building the AI Chat API</h3>
|
|
1257
|
+
|
|
1258
|
+
<div class="explanation">
|
|
1259
|
+
<div class="explanation-title">A Real Story</div>
|
|
1260
|
+
<p>
|
|
1261
|
+
Let's walk through what actually happened when we built an AI chat API
|
|
1262
|
+
using the <strong>Vercel AI SDK</strong>. This shows both <strong>what worked</strong>
|
|
1263
|
+
and <strong>what the system caught</strong> that would have been missed otherwise.
|
|
1264
|
+
</p>
|
|
1265
|
+
</div>
|
|
1266
|
+
|
|
1267
|
+
<div class="walkthrough-step">
|
|
1268
|
+
<div class="walkthrough-header">
|
|
1269
|
+
<div class="walkthrough-num">1</div>
|
|
1270
|
+
<div class="walkthrough-title">User Request</div>
|
|
1271
|
+
</div>
|
|
1272
|
+
<div class="walkthrough-content">
|
|
1273
|
+
<div class="walkthrough-desc">
|
|
1274
|
+
The user asked for an AI chat API with multi-provider support
|
|
1275
|
+
using a <strong>single API key via Vercel AI Gateway</strong>.
|
|
1276
|
+
</div>
|
|
1277
|
+
<div class="walkthrough-example">
|
|
1278
|
+
<div class="label">User Said:</div>
|
|
1279
|
+
"I want to use OpenAI, Anthropic, Google, Perplexity - all <strong>via Vercel AI Gateway</strong>
|
|
1280
|
+
so I only need one API key instead of four."
|
|
1281
|
+
</div>
|
|
1282
|
+
</div>
|
|
1283
|
+
</div>
|
|
1284
|
+
|
|
1285
|
+
<div class="walkthrough-step">
|
|
1286
|
+
<div class="walkthrough-header">
|
|
1287
|
+
<div class="walkthrough-num">2</div>
|
|
1288
|
+
<div class="walkthrough-title">Research Phase</div>
|
|
1289
|
+
</div>
|
|
1290
|
+
<div class="walkthrough-content">
|
|
1291
|
+
<div class="walkthrough-desc">
|
|
1292
|
+
System forced the AI to research before writing any code.
|
|
1293
|
+
It fetched live documentation from Context7 and searched the web.
|
|
1294
|
+
</div>
|
|
1295
|
+
<div class="walkthrough-example">
|
|
1296
|
+
<div class="label">Research Sources Logged:</div>
|
|
1297
|
+
- Context7: Vercel AI SDK docs<br>
|
|
1298
|
+
- WebSearch: GPT-5.1 models<br>
|
|
1299
|
+
- WebSearch: Gemini 3 Pro<br>
|
|
1300
|
+
- Context7: generateText, streamText functions
|
|
1301
|
+
</div>
|
|
1302
|
+
</div>
|
|
1303
|
+
</div>
|
|
1304
|
+
|
|
1305
|
+
<div class="walkthrough-step">
|
|
1306
|
+
<div class="walkthrough-header">
|
|
1307
|
+
<div class="walkthrough-num">3</div>
|
|
1308
|
+
<div class="walkthrough-title">Interview Phase</div>
|
|
1309
|
+
</div>
|
|
1310
|
+
<div class="walkthrough-content">
|
|
1311
|
+
<div class="walkthrough-desc">
|
|
1312
|
+
AI asked 6 questions about requirements.
|
|
1313
|
+
User specified: providers, capabilities, streaming modes, default models.
|
|
1314
|
+
</div>
|
|
1315
|
+
<div class="walkthrough-example">
|
|
1316
|
+
<div class="label">Interview Results Recorded:</div>
|
|
1317
|
+
- Providers: OpenAI, Anthropic, Google, Perplexity <strong>via Vercel AI Gateway</strong><br>
|
|
1318
|
+
- Capabilities: Chat, image, speech, transcription, embeddings<br>
|
|
1319
|
+
- Default model: Budget tier for cost efficiency
|
|
1320
|
+
</div>
|
|
1321
|
+
</div>
|
|
1322
|
+
</div>
|
|
1323
|
+
|
|
1324
|
+
<div class="walkthrough-step" style="border-color: var(--white);">
|
|
1325
|
+
<div class="walkthrough-header">
|
|
1326
|
+
<div class="walkthrough-num">!</div>
|
|
1327
|
+
<div class="walkthrough-title">Gap Detected</div>
|
|
1328
|
+
</div>
|
|
1329
|
+
<div class="walkthrough-content">
|
|
1330
|
+
<div class="walkthrough-desc">
|
|
1331
|
+
The AI wrote the implementation using <strong>direct provider SDKs</strong>
|
|
1332
|
+
instead of the Vercel AI Gateway. The verification hook caught this mismatch!
|
|
1333
|
+
</div>
|
|
1334
|
+
<div class="walkthrough-example">
|
|
1335
|
+
<div class="label">What Happened:</div>
|
|
1336
|
+
Interview said: "via Vercel AI Gateway"<br>
|
|
1337
|
+
Code used: @ai-sdk/openai, @ai-sdk/anthropic (direct calls)<br><br>
|
|
1338
|
+
<strong>DETECTED:</strong> Implementation doesn't match interview requirements!
|
|
1339
|
+
</div>
|
|
1340
|
+
</div>
|
|
1341
|
+
</div>
|
|
1342
|
+
|
|
1343
|
+
<div class="walkthrough-step">
|
|
1344
|
+
<div class="walkthrough-header">
|
|
1345
|
+
<div class="walkthrough-num">4</div>
|
|
1346
|
+
<div class="walkthrough-title">Fixed Implementation</div>
|
|
1347
|
+
</div>
|
|
1348
|
+
<div class="walkthrough-content">
|
|
1349
|
+
<div class="walkthrough-desc">
|
|
1350
|
+
After the gap was caught, the code was updated to actually use
|
|
1351
|
+
<strong>@ai-sdk/gateway</strong> with a single API key.
|
|
1352
|
+
</div>
|
|
1353
|
+
<div class="walkthrough-example">
|
|
1354
|
+
<div class="label">Corrected Code:</div>
|
|
1355
|
+
import { gateway } from '@ai-sdk/gateway';<br>
|
|
1356
|
+
const client = createAIClient({ apiKey: AI_GATEWAY_API_KEY });
|
|
1357
|
+
</div>
|
|
1358
|
+
</div>
|
|
1359
|
+
</div>
|
|
1360
|
+
|
|
1361
|
+
<div class="walkthrough-step">
|
|
1362
|
+
<div class="walkthrough-header">
|
|
1363
|
+
<div class="walkthrough-num">5</div>
|
|
1364
|
+
<div class="walkthrough-title">Final Result</div>
|
|
1365
|
+
</div>
|
|
1366
|
+
<div class="walkthrough-content">
|
|
1367
|
+
<div class="walkthrough-desc">
|
|
1368
|
+
Complete implementation with 160 tests, proper documentation,
|
|
1369
|
+
and code that actually matches what the user asked for.
|
|
1370
|
+
</div>
|
|
1371
|
+
<div class="walkthrough-example">
|
|
1372
|
+
<div class="label">Files Created:</div>
|
|
1373
|
+
- src/lib/ai/client.ts (gateway implementation)<br>
|
|
1374
|
+
- src/lib/ai/schemas.ts (Zod validation)<br>
|
|
1375
|
+
- src/app/api/v2/ai/chat/route.ts<br>
|
|
1376
|
+
- 160 tests passing
|
|
1377
|
+
</div>
|
|
1378
|
+
</div>
|
|
1379
|
+
</div>
|
|
1380
|
+
</div>
|
|
1381
|
+
</section>
|
|
1382
|
+
|
|
1383
|
+
<!-- ============================================
|
|
1384
|
+
SECTION 7: TERMINAL SIMULATION
|
|
1385
|
+
============================================ -->
|
|
1386
|
+
<section id="demo">
|
|
1387
|
+
<div class="ascii-border">
|
|
1388
|
+
<h2>LIVE SIMULATION</h2>
|
|
1389
|
+
<h3>See the Hooks in Action</h3>
|
|
1390
|
+
|
|
1391
|
+
<div class="explanation">
|
|
1392
|
+
<div class="explanation-title">Watch the Enforcement</div>
|
|
1393
|
+
<p>
|
|
1394
|
+
This simulates what happens during a Claude Code session.
|
|
1395
|
+
Notice how actions get <strong>BLOCKED</strong> until prerequisites are met,
|
|
1396
|
+
and how everything gets <strong>LOGGED</strong> for verification.
|
|
1397
|
+
</p>
|
|
1398
|
+
</div>
|
|
1399
|
+
|
|
1400
|
+
<div class="terminal">
|
|
1401
|
+
<div class="terminal-header">
|
|
1402
|
+
<div class="terminal-dot"></div>
|
|
1403
|
+
<div class="terminal-dot"></div>
|
|
1404
|
+
<div class="terminal-dot"></div>
|
|
1405
|
+
<div class="terminal-title">claude-code session</div>
|
|
1406
|
+
</div>
|
|
1407
|
+
|
|
1408
|
+
<div class="terminal-comment" data-step="0">// AI tries to write code immediately</div>
|
|
1409
|
+
<div class="terminal-line" data-step="1">
|
|
1410
|
+
<span class="terminal-prompt">claude></span>
|
|
1411
|
+
<span class="terminal-command">Write src/app/api/v2/ai/chat/route.ts</span>
|
|
1412
|
+
</div>
|
|
1413
|
+
<div class="terminal-line terminal-result" data-step="2">
|
|
1414
|
+
<span class="terminal-blocked">BLOCKED: Research phase not complete.<br>Run /api-research first to fetch live documentation.</span>
|
|
1415
|
+
</div>
|
|
1416
|
+
|
|
1417
|
+
<div class="terminal-comment" data-step="3">// AI does research - gets logged</div>
|
|
1418
|
+
<div class="terminal-line" data-step="4">
|
|
1419
|
+
<span class="terminal-prompt">claude></span>
|
|
1420
|
+
<span class="terminal-command">WebSearch "Vercel AI Gateway documentation"</span>
|
|
1421
|
+
</div>
|
|
1422
|
+
<div class="terminal-line terminal-result" data-step="5">
|
|
1423
|
+
<span class="terminal-logged">[LOGGED] Research source added to api-dev-state.json</span>
|
|
1424
|
+
</div>
|
|
1425
|
+
|
|
1426
|
+
<div class="terminal-comment" data-step="6">// AI tries to write code again</div>
|
|
1427
|
+
<div class="terminal-line" data-step="7">
|
|
1428
|
+
<span class="terminal-prompt">claude></span>
|
|
1429
|
+
<span class="terminal-command">Write src/app/api/v2/ai/chat/route.ts</span>
|
|
1430
|
+
</div>
|
|
1431
|
+
<div class="terminal-line terminal-result" data-step="8">
|
|
1432
|
+
<span class="terminal-blocked">BLOCKED: Interview phase not complete.<br>Use AskUserQuestion to understand requirements.</span>
|
|
1433
|
+
</div>
|
|
1434
|
+
|
|
1435
|
+
<div class="terminal-comment" data-step="9">// AI asks user a question</div>
|
|
1436
|
+
<div class="terminal-line" data-step="10">
|
|
1437
|
+
<span class="terminal-prompt">claude></span>
|
|
1438
|
+
<span class="terminal-command">AskUserQuestion "Which providers should this support?"</span>
|
|
1439
|
+
</div>
|
|
1440
|
+
<div class="terminal-line terminal-result" data-step="11">
|
|
1441
|
+
<span class="terminal-logged">[TRACKED] Question logged with tool_used: true</span>
|
|
1442
|
+
</div>
|
|
1443
|
+
|
|
1444
|
+
<div class="terminal-comment" data-step="12">// After 3+ questions, AI can write code</div>
|
|
1445
|
+
<div class="terminal-line" data-step="13">
|
|
1446
|
+
<span class="terminal-prompt">claude></span>
|
|
1447
|
+
<span class="terminal-command">Write src/app/api/v2/ai/chat/route.ts</span>
|
|
1448
|
+
</div>
|
|
1449
|
+
<div class="terminal-line terminal-result" data-step="14">
|
|
1450
|
+
<span class="terminal-allowed">ALLOWED: All prerequisites met. Writing file...</span>
|
|
1451
|
+
</div>
|
|
1452
|
+
|
|
1453
|
+
<div class="terminal-comment" data-step="15">// AI tries to stop before finishing all phases</div>
|
|
1454
|
+
<div class="terminal-line" data-step="16">
|
|
1455
|
+
<span class="terminal-prompt">claude></span>
|
|
1456
|
+
<span class="terminal-command">[STOP - end conversation]</span>
|
|
1457
|
+
</div>
|
|
1458
|
+
<div class="terminal-line terminal-result" data-step="17">
|
|
1459
|
+
<span class="terminal-blocked">BLOCKED: Required phases incomplete.<br>- TDD Green phase (not started)<br>- Documentation (not started)</span>
|
|
1460
|
+
</div>
|
|
1461
|
+
|
|
1462
|
+
<div class="terminal-comment" data-step="18">// After completing all phases</div>
|
|
1463
|
+
<div class="terminal-line" data-step="19">
|
|
1464
|
+
<span class="terminal-prompt">claude></span>
|
|
1465
|
+
<span class="terminal-command">[STOP - all phases complete]</span>
|
|
1466
|
+
</div>
|
|
1467
|
+
<div class="terminal-line terminal-result" data-step="20">
|
|
1468
|
+
<span class="terminal-allowed">ALLOWED: Workflow complete!<br>Files created: 12 | Tests: 160 passing</span>
|
|
1469
|
+
</div>
|
|
1470
|
+
</div>
|
|
1471
|
+
</div>
|
|
1472
|
+
</section>
|
|
1473
|
+
|
|
1474
|
+
<!-- ============================================
|
|
1475
|
+
SECTION 8: STATE FILE
|
|
1476
|
+
============================================ -->
|
|
1477
|
+
<section id="state">
|
|
1478
|
+
<div class="ascii-border">
|
|
1479
|
+
<h2>TRACKING PROGRESS</h2>
|
|
1480
|
+
<h3>The State File</h3>
|
|
1481
|
+
|
|
1482
|
+
<div class="explanation">
|
|
1483
|
+
<div class="explanation-title">Everything Gets Recorded</div>
|
|
1484
|
+
<p>
|
|
1485
|
+
All progress is saved to <code>.claude/api-dev-state.json</code>.
|
|
1486
|
+
This creates an <strong>audit trail</strong> of what was researched, what questions
|
|
1487
|
+
were asked, and what was built. You can always check the current state.
|
|
1488
|
+
</p>
|
|
1489
|
+
</div>
|
|
1490
|
+
|
|
1491
|
+
<div class="json-viewer">
|
|
1492
|
+
<div class="json-line"><span class="json-key">{</span></div>
|
|
1493
|
+
<div class="json-line"> <span class="json-key">"endpoint":</span> <span class="json-string">"ai-foundation"</span>,</div>
|
|
1494
|
+
<div class="json-line"> <span class="json-key">"library":</span> <span class="json-string">"Vercel AI SDK"</span>,</div>
|
|
1495
|
+
<div class="json-line"> <span class="json-key">"phases":</span> {</div>
|
|
1496
|
+
<div class="json-line highlight"> <span class="json-key">"research_initial":</span> { <span class="json-key">"status":</span> <span class="json-value">"complete"</span> }, <span class="json-comment">// Logged 6 sources</span></div>
|
|
1497
|
+
<div class="json-line highlight"> <span class="json-key">"interview":</span> {</div>
|
|
1498
|
+
<div class="json-line highlight"> <span class="json-key">"status":</span> <span class="json-value">"complete"</span>,</div>
|
|
1499
|
+
<div class="json-line highlight"> <span class="json-key">"user_question_count":</span> <span class="json-value">6</span> <span class="json-comment">// Actual questions asked</span></div>
|
|
1500
|
+
<div class="json-line highlight"> },</div>
|
|
1501
|
+
<div class="json-line highlight"> <span class="json-key">"tdd_red":</span> { <span class="json-key">"status":</span> <span class="json-value">"complete"</span>, <span class="json-key">"tests_count":</span> <span class="json-value">146</span> },</div>
|
|
1502
|
+
<div class="json-line highlight"> <span class="json-key">"tdd_green":</span> { <span class="json-key">"status":</span> <span class="json-value">"complete"</span> }</div>
|
|
1503
|
+
<div class="json-line"> },</div>
|
|
1504
|
+
<div class="json-line"> <span class="json-key">"verification":</span> {</div>
|
|
1505
|
+
<div class="json-line"> <span class="json-key">"all_sources_fetched":</span> <span class="json-value">true</span>,</div>
|
|
1506
|
+
<div class="json-line"> <span class="json-key">"all_tests_passing":</span> <span class="json-value">true</span></div>
|
|
1507
|
+
<div class="json-line"> },</div>
|
|
1508
|
+
<div class="json-line"> <span class="json-key">"files_created":</span> [</div>
|
|
1509
|
+
<div class="json-line"> <span class="json-string">"src/lib/ai/client.ts"</span>,</div>
|
|
1510
|
+
<div class="json-line"> <span class="json-string">"src/lib/ai/schemas.ts"</span>,</div>
|
|
1511
|
+
<div class="json-line"> <span class="json-string">"src/app/api/v2/ai/chat/route.ts"</span>,</div>
|
|
1512
|
+
<div class="json-line"> <span class="json-string">"... and 9 more"</span></div>
|
|
1513
|
+
<div class="json-line"> ]</div>
|
|
1514
|
+
<div class="json-line"><span class="json-key">}</span></div>
|
|
1515
|
+
</div>
|
|
1516
|
+
</div>
|
|
1517
|
+
</section>
|
|
1518
|
+
|
|
1519
|
+
<!-- ============================================
|
|
1520
|
+
SECTION 9: INSTALLATION
|
|
1521
|
+
============================================ -->
|
|
1522
|
+
<section id="install">
|
|
1523
|
+
<div class="ascii-border">
|
|
1524
|
+
<h2>GET STARTED</h2>
|
|
1525
|
+
<h3>One Command Installation</h3>
|
|
1526
|
+
|
|
1527
|
+
<div class="explanation">
|
|
1528
|
+
<div class="explanation-title">Easy Setup</div>
|
|
1529
|
+
<p>
|
|
1530
|
+
Run a single command to install everything. The installer copies slash commands,
|
|
1531
|
+
Python hooks, and configures the system automatically.
|
|
1532
|
+
<strong>Works with any project.</strong>
|
|
1533
|
+
</p>
|
|
1534
|
+
</div>
|
|
1535
|
+
|
|
1536
|
+
<div class="install-command">
|
|
1537
|
+
<code>npx @hustle-together/api-dev-tools --scope=project</code>
|
|
1538
|
+
</div>
|
|
1539
|
+
|
|
1540
|
+
<div class="install-flow">
|
|
1541
|
+
<div class="install-step">
|
|
1542
|
+
<div class="install-icon">21</div>
|
|
1543
|
+
<div class="install-content">
|
|
1544
|
+
<div class="install-from">Slash Commands</div>
|
|
1545
|
+
<div class="install-note">/api-create, /api-interview, /red, /green, /refactor...</div>
|
|
1546
|
+
</div>
|
|
1547
|
+
<div class="install-arrow">---></div>
|
|
1548
|
+
<div class="install-to">.claude/commands/</div>
|
|
1549
|
+
</div>
|
|
1550
|
+
<div class="install-step">
|
|
1551
|
+
<div class="install-icon">5</div>
|
|
1552
|
+
<div class="install-content">
|
|
1553
|
+
<div class="install-from">Python Hooks</div>
|
|
1554
|
+
<div class="install-note">enforce-research, enforce-interview, verify-implementation...</div>
|
|
1555
|
+
</div>
|
|
1556
|
+
<div class="install-arrow">---></div>
|
|
1557
|
+
<div class="install-to">.claude/hooks/</div>
|
|
1558
|
+
</div>
|
|
1559
|
+
<div class="install-step">
|
|
1560
|
+
<div class="install-icon">+</div>
|
|
1561
|
+
<div class="install-content">
|
|
1562
|
+
<div class="install-from">Settings Configuration</div>
|
|
1563
|
+
<div class="install-note">Hook registration, permissions, matchers</div>
|
|
1564
|
+
</div>
|
|
1565
|
+
<div class="install-arrow">---></div>
|
|
1566
|
+
<div class="install-to">.claude/settings.json</div>
|
|
1567
|
+
</div>
|
|
1568
|
+
<div class="install-step">
|
|
1569
|
+
<div class="install-icon">*</div>
|
|
1570
|
+
<div class="install-content">
|
|
1571
|
+
<div class="install-from">MCP Servers</div>
|
|
1572
|
+
<div class="install-note">Context7 (live docs), GitHub (issues/PRs)</div>
|
|
1573
|
+
</div>
|
|
1574
|
+
<div class="install-arrow">---></div>
|
|
1575
|
+
<div class="install-to">claude mcp add</div>
|
|
1576
|
+
</div>
|
|
1577
|
+
</div>
|
|
1578
|
+
</div>
|
|
1579
|
+
</section>
|
|
1580
|
+
|
|
1581
|
+
<!-- ============================================
|
|
1582
|
+
SECTION 10: FINAL / LINKS
|
|
1583
|
+
============================================ -->
|
|
1584
|
+
<section id="credits">
|
|
1585
|
+
<div class="ascii-border" style="text-align: center;">
|
|
1586
|
+
<h2>START BUILDING BETTER APIs</h2>
|
|
1587
|
+
|
|
1588
|
+
<div class="explanation" style="text-align: left;">
|
|
1589
|
+
<div class="explanation-title">What You Get</div>
|
|
1590
|
+
<p>
|
|
1591
|
+
<strong>Structured workflow</strong> - No more skipped steps or assumptions<br>
|
|
1592
|
+
<strong>Real enforcement</strong> - Hooks that actually block bad behavior<br>
|
|
1593
|
+
<strong>Audit trail</strong> - Every action logged to state file<br>
|
|
1594
|
+
<strong>Gap detection</strong> - Catches mismatches between requirements and code<br>
|
|
1595
|
+
<strong>TDD built-in</strong> - Tests written before implementation
|
|
1596
|
+
</p>
|
|
1597
|
+
</div>
|
|
1598
|
+
|
|
1599
|
+
<div class="credit-links">
|
|
1600
|
+
<a href="https://github.com/hustle-together/api-dev-tools" class="credit-link" target="_blank">VIEW ON GITHUB</a>
|
|
1601
|
+
<a href="https://www.npmjs.com/package/@hustle-together/api-dev-tools" class="credit-link" target="_blank">INSTALL FROM NPM</a>
|
|
1602
|
+
</div>
|
|
1603
|
+
|
|
1604
|
+
<div class="made-with">
|
|
1605
|
+
<p>Made for developers who want AI assistants<br>that actually follow instructions.</p>
|
|
1606
|
+
<p style="margin-top: 20px; color: var(--dark-grey);">
|
|
1607
|
+
v1.6.0 | MIT License<br>
|
|
1608
|
+
"Interview first, test first, document always"
|
|
1609
|
+
</p>
|
|
1610
|
+
</div>
|
|
1611
|
+
</div>
|
|
1612
|
+
</section>
|
|
1613
|
+
|
|
1614
|
+
<script>
|
|
1615
|
+
// Register GSAP plugins
|
|
1616
|
+
gsap.registerPlugin(ScrollTrigger, TextPlugin);
|
|
1617
|
+
|
|
1618
|
+
// ============================================
|
|
1619
|
+
// CONFIGURATION
|
|
1620
|
+
// ============================================
|
|
1621
|
+
const sections = ['intro', 'problems', 'solution', 'hooks', 'phases', 'walkthrough', 'demo', 'state', 'install', 'credits'];
|
|
1622
|
+
let isPlaying = false;
|
|
1623
|
+
|
|
1624
|
+
// ============================================
|
|
1625
|
+
// SECTION INDICATORS
|
|
1626
|
+
// ============================================
|
|
1627
|
+
const indicatorContainer = document.getElementById('sectionIndicator');
|
|
1628
|
+
sections.forEach((id, i) => {
|
|
1629
|
+
const dot = document.createElement('div');
|
|
1630
|
+
dot.className = 'section-dot';
|
|
1631
|
+
dot.dataset.section = id;
|
|
1632
|
+
dot.title = id.charAt(0).toUpperCase() + id.slice(1);
|
|
1633
|
+
dot.addEventListener('click', () => {
|
|
1634
|
+
document.getElementById(id).scrollIntoView({ behavior: 'smooth' });
|
|
1635
|
+
});
|
|
1636
|
+
indicatorContainer.appendChild(dot);
|
|
1637
|
+
});
|
|
1638
|
+
|
|
1639
|
+
// Update active indicator on scroll
|
|
1640
|
+
ScrollTrigger.create({
|
|
1641
|
+
trigger: 'body',
|
|
1642
|
+
start: 'top top',
|
|
1643
|
+
end: 'bottom bottom',
|
|
1644
|
+
onUpdate: (self) => {
|
|
1645
|
+
const progress = self.progress;
|
|
1646
|
+
const currentIndex = Math.min(Math.floor(progress * sections.length), sections.length - 1);
|
|
1647
|
+
document.querySelectorAll('.section-dot').forEach((dot, i) => {
|
|
1648
|
+
dot.classList.toggle('active', i === currentIndex);
|
|
1649
|
+
});
|
|
1650
|
+
document.getElementById('progressBar').style.width = `${progress * 100}%`;
|
|
1651
|
+
}
|
|
1652
|
+
});
|
|
1653
|
+
|
|
1654
|
+
// ============================================
|
|
1655
|
+
// SECTION 1: INTRO ANIMATION
|
|
1656
|
+
// ============================================
|
|
1657
|
+
const introTL = gsap.timeline({
|
|
1658
|
+
scrollTrigger: {
|
|
1659
|
+
trigger: '#intro',
|
|
1660
|
+
start: 'top 80%',
|
|
1661
|
+
toggleActions: 'play none none reverse'
|
|
1662
|
+
}
|
|
1663
|
+
});
|
|
1664
|
+
|
|
1665
|
+
introTL
|
|
1666
|
+
.to('#intro h1', { opacity: 1, duration: 0.6 })
|
|
1667
|
+
.to('#packageName', { opacity: 1, duration: 0.5 }, '-=0.3')
|
|
1668
|
+
.to('#versionText', { opacity: 1, duration: 0.3 })
|
|
1669
|
+
.to('.intro-text', { opacity: 1, duration: 0.6 }, '-=0.2')
|
|
1670
|
+
.to('.scroll-hint', { opacity: 1, duration: 0.4 });
|
|
1671
|
+
|
|
1672
|
+
// ============================================
|
|
1673
|
+
// SECTION 2: PROBLEMS ANIMATION
|
|
1674
|
+
// ============================================
|
|
1675
|
+
const problemsTL = gsap.timeline({
|
|
1676
|
+
scrollTrigger: {
|
|
1677
|
+
trigger: '#problems',
|
|
1678
|
+
start: 'top 60%',
|
|
1679
|
+
toggleActions: 'play none none reverse'
|
|
1680
|
+
}
|
|
1681
|
+
});
|
|
1682
|
+
|
|
1683
|
+
problemsTL.to('#problems .explanation', { opacity: 1, duration: 0.5 });
|
|
1684
|
+
|
|
1685
|
+
document.querySelectorAll('.gap-item').forEach((item, i) => {
|
|
1686
|
+
problemsTL.to(item, {
|
|
1687
|
+
opacity: 1,
|
|
1688
|
+
x: 0,
|
|
1689
|
+
duration: 0.4,
|
|
1690
|
+
ease: 'power2.out'
|
|
1691
|
+
}, i * 0.2 + 0.3);
|
|
1692
|
+
});
|
|
1693
|
+
|
|
1694
|
+
// ============================================
|
|
1695
|
+
// SECTION 3: SOLUTION ANIMATION
|
|
1696
|
+
// ============================================
|
|
1697
|
+
const solutionTL = gsap.timeline({
|
|
1698
|
+
scrollTrigger: {
|
|
1699
|
+
trigger: '#solution',
|
|
1700
|
+
start: 'top 60%',
|
|
1701
|
+
toggleActions: 'play none none reverse'
|
|
1702
|
+
}
|
|
1703
|
+
});
|
|
1704
|
+
|
|
1705
|
+
solutionTL.to('#solution .explanation', { opacity: 1, duration: 0.5 });
|
|
1706
|
+
|
|
1707
|
+
document.querySelectorAll('.solution-card').forEach((card, i) => {
|
|
1708
|
+
solutionTL.to(card, {
|
|
1709
|
+
opacity: 1,
|
|
1710
|
+
y: 0,
|
|
1711
|
+
duration: 0.4,
|
|
1712
|
+
ease: 'power2.out'
|
|
1713
|
+
}, i * 0.15 + 0.3);
|
|
1714
|
+
});
|
|
1715
|
+
|
|
1716
|
+
// ============================================
|
|
1717
|
+
// SECTION 4: HOOKS ANIMATION
|
|
1718
|
+
// ============================================
|
|
1719
|
+
const hooksTL = gsap.timeline({
|
|
1720
|
+
scrollTrigger: {
|
|
1721
|
+
trigger: '#hooks',
|
|
1722
|
+
start: 'top 60%',
|
|
1723
|
+
toggleActions: 'play none none reverse'
|
|
1724
|
+
}
|
|
1725
|
+
});
|
|
1726
|
+
|
|
1727
|
+
hooksTL
|
|
1728
|
+
.to('#hooks .explanation', { opacity: 1, duration: 0.5 })
|
|
1729
|
+
.to('#hooks .flow-box', { opacity: 1, stagger: 0.2, duration: 0.3 })
|
|
1730
|
+
.to('#hooks .flow-arrow', { opacity: 1, stagger: 0.1, duration: 0.2 }, '-=0.3')
|
|
1731
|
+
.to('#hooks .hook-group', { opacity: 1, stagger: 0.25, duration: 0.4 })
|
|
1732
|
+
.to('#hooks .hook-file', { opacity: 1, stagger: 0.08, duration: 0.2 })
|
|
1733
|
+
.to('#hooks .result-allowed, #hooks .result-blocked', { opacity: 1, stagger: 0.15, duration: 0.3 });
|
|
1734
|
+
|
|
1735
|
+
// ============================================
|
|
1736
|
+
// SECTION 5: PHASES ANIMATION
|
|
1737
|
+
// ============================================
|
|
1738
|
+
const phasesTL = gsap.timeline({
|
|
1739
|
+
scrollTrigger: {
|
|
1740
|
+
trigger: '#phases',
|
|
1741
|
+
start: 'top 60%',
|
|
1742
|
+
toggleActions: 'play none none reverse'
|
|
1743
|
+
}
|
|
1744
|
+
});
|
|
1745
|
+
|
|
1746
|
+
phasesTL.to('#phases .explanation', { opacity: 1, duration: 0.5 });
|
|
1747
|
+
|
|
1748
|
+
document.querySelectorAll('.phase-box').forEach((box, i) => {
|
|
1749
|
+
phasesTL.to(box, {
|
|
1750
|
+
opacity: 1,
|
|
1751
|
+
scale: 1,
|
|
1752
|
+
duration: 0.25,
|
|
1753
|
+
ease: 'back.out(1.5)',
|
|
1754
|
+
onComplete: () => {
|
|
1755
|
+
box.classList.add('active');
|
|
1756
|
+
box.querySelector('.phase-status').textContent = '[OK]';
|
|
1757
|
+
}
|
|
1758
|
+
}, i * 0.1 + 0.3);
|
|
1759
|
+
});
|
|
1760
|
+
|
|
1761
|
+
phasesTL.to('.phase-connector', { opacity: 1, duration: 0.3 }, '-=0.8');
|
|
1762
|
+
|
|
1763
|
+
// ============================================
|
|
1764
|
+
// SECTION 6: WALKTHROUGH ANIMATION
|
|
1765
|
+
// ============================================
|
|
1766
|
+
const walkthroughTL = gsap.timeline({
|
|
1767
|
+
scrollTrigger: {
|
|
1768
|
+
trigger: '#walkthrough',
|
|
1769
|
+
start: 'top 60%',
|
|
1770
|
+
toggleActions: 'play none none reverse'
|
|
1771
|
+
}
|
|
1772
|
+
});
|
|
1773
|
+
|
|
1774
|
+
walkthroughTL.to('#walkthrough .explanation', { opacity: 1, duration: 0.5 });
|
|
1775
|
+
|
|
1776
|
+
document.querySelectorAll('.walkthrough-step').forEach((step, i) => {
|
|
1777
|
+
walkthroughTL.to(step, {
|
|
1778
|
+
opacity: 1,
|
|
1779
|
+
y: 0,
|
|
1780
|
+
duration: 0.4,
|
|
1781
|
+
ease: 'power2.out'
|
|
1782
|
+
}, i * 0.25 + 0.3);
|
|
1783
|
+
});
|
|
1784
|
+
|
|
1785
|
+
// ============================================
|
|
1786
|
+
// SECTION 7: DEMO TERMINAL ANIMATION
|
|
1787
|
+
// ============================================
|
|
1788
|
+
const demoTL = gsap.timeline({
|
|
1789
|
+
scrollTrigger: {
|
|
1790
|
+
trigger: '#demo',
|
|
1791
|
+
start: 'top 60%',
|
|
1792
|
+
toggleActions: 'play none none reverse'
|
|
1793
|
+
}
|
|
1794
|
+
});
|
|
1795
|
+
|
|
1796
|
+
demoTL.to('#demo .explanation', { opacity: 1, duration: 0.5 });
|
|
1797
|
+
|
|
1798
|
+
// Get all terminal elements in order
|
|
1799
|
+
const terminalElements = document.querySelectorAll('#demo .terminal-comment, #demo .terminal-line');
|
|
1800
|
+
terminalElements.forEach((el, i) => {
|
|
1801
|
+
const delay = i * 0.25 + 0.5;
|
|
1802
|
+
demoTL.to(el, {
|
|
1803
|
+
opacity: 1,
|
|
1804
|
+
duration: 0.3,
|
|
1805
|
+
ease: 'power2.out'
|
|
1806
|
+
}, delay);
|
|
1807
|
+
});
|
|
1808
|
+
|
|
1809
|
+
// ============================================
|
|
1810
|
+
// SECTION 8: STATE FILE ANIMATION
|
|
1811
|
+
// ============================================
|
|
1812
|
+
const stateTL = gsap.timeline({
|
|
1813
|
+
scrollTrigger: {
|
|
1814
|
+
trigger: '#state',
|
|
1815
|
+
start: 'top 60%',
|
|
1816
|
+
toggleActions: 'play none none reverse'
|
|
1817
|
+
}
|
|
1818
|
+
});
|
|
1819
|
+
|
|
1820
|
+
stateTL.to('#state .explanation', { opacity: 1, duration: 0.5 });
|
|
1821
|
+
|
|
1822
|
+
document.querySelectorAll('.json-line').forEach((line, i) => {
|
|
1823
|
+
stateTL.to(line, {
|
|
1824
|
+
opacity: 1,
|
|
1825
|
+
duration: 0.12
|
|
1826
|
+
}, i * 0.06 + 0.4);
|
|
1827
|
+
});
|
|
1828
|
+
|
|
1829
|
+
// ============================================
|
|
1830
|
+
// SECTION 9: INSTALL ANIMATION
|
|
1831
|
+
// ============================================
|
|
1832
|
+
const installTL = gsap.timeline({
|
|
1833
|
+
scrollTrigger: {
|
|
1834
|
+
trigger: '#install',
|
|
1835
|
+
start: 'top 60%',
|
|
1836
|
+
toggleActions: 'play none none reverse'
|
|
1837
|
+
}
|
|
1838
|
+
});
|
|
1839
|
+
|
|
1840
|
+
installTL.to('#install .explanation', { opacity: 1, duration: 0.5 });
|
|
1841
|
+
|
|
1842
|
+
document.querySelectorAll('.install-step').forEach((step, i) => {
|
|
1843
|
+
installTL.to(step, {
|
|
1844
|
+
opacity: 1,
|
|
1845
|
+
y: 0,
|
|
1846
|
+
duration: 0.4,
|
|
1847
|
+
ease: 'power2.out'
|
|
1848
|
+
}, i * 0.2 + 0.4);
|
|
1849
|
+
});
|
|
1850
|
+
|
|
1851
|
+
// ============================================
|
|
1852
|
+
// SECTION 10: CREDITS ANIMATION
|
|
1853
|
+
// ============================================
|
|
1854
|
+
const creditsTL = gsap.timeline({
|
|
1855
|
+
scrollTrigger: {
|
|
1856
|
+
trigger: '#credits',
|
|
1857
|
+
start: 'top 60%',
|
|
1858
|
+
toggleActions: 'play none none reverse'
|
|
1859
|
+
}
|
|
1860
|
+
});
|
|
1861
|
+
|
|
1862
|
+
creditsTL
|
|
1863
|
+
.to('#credits .explanation', { opacity: 1, duration: 0.5 })
|
|
1864
|
+
.to('.credit-link', { opacity: 1, stagger: 0.15, duration: 0.4 })
|
|
1865
|
+
.to('.made-with', { opacity: 1, duration: 0.5 });
|
|
1866
|
+
|
|
1867
|
+
// ============================================
|
|
1868
|
+
// AUTO-PLAY BUTTON
|
|
1869
|
+
// ============================================
|
|
1870
|
+
document.getElementById('playBtn').addEventListener('click', () => {
|
|
1871
|
+
if (!isPlaying) {
|
|
1872
|
+
isPlaying = true;
|
|
1873
|
+
document.getElementById('playBtn').textContent = 'PLAYING...';
|
|
1874
|
+
document.getElementById('playBtn').style.background = 'var(--white)';
|
|
1875
|
+
document.getElementById('playBtn').style.color = 'var(--black)';
|
|
1876
|
+
|
|
1877
|
+
let currentSection = 0;
|
|
1878
|
+
const autoScroll = setInterval(() => {
|
|
1879
|
+
if (currentSection < sections.length) {
|
|
1880
|
+
document.getElementById(sections[currentSection]).scrollIntoView({
|
|
1881
|
+
behavior: 'smooth'
|
|
1882
|
+
});
|
|
1883
|
+
currentSection++;
|
|
1884
|
+
} else {
|
|
1885
|
+
clearInterval(autoScroll);
|
|
1886
|
+
isPlaying = false;
|
|
1887
|
+
document.getElementById('playBtn').textContent = 'AUTO PLAY';
|
|
1888
|
+
document.getElementById('playBtn').style.background = 'transparent';
|
|
1889
|
+
document.getElementById('playBtn').style.color = 'var(--white)';
|
|
1890
|
+
}
|
|
1891
|
+
}, 5000);
|
|
1892
|
+
}
|
|
1893
|
+
});
|
|
1894
|
+
|
|
1895
|
+
// ============================================
|
|
1896
|
+
// RESET BUTTON
|
|
1897
|
+
// ============================================
|
|
1898
|
+
document.getElementById('resetBtn').addEventListener('click', () => {
|
|
1899
|
+
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
1900
|
+
|
|
1901
|
+
// Reset animations
|
|
1902
|
+
setTimeout(() => {
|
|
1903
|
+
gsap.set('.explanation', { opacity: 0 });
|
|
1904
|
+
gsap.set('.gap-item', { opacity: 0, x: -30 });
|
|
1905
|
+
gsap.set('.solution-card', { opacity: 0, y: 20 });
|
|
1906
|
+
gsap.set('.flow-box, .flow-arrow, .hook-group, .hook-file', { opacity: 0 });
|
|
1907
|
+
gsap.set('.result-allowed, .result-blocked', { opacity: 0 });
|
|
1908
|
+
gsap.set('.phase-box', { opacity: 0, scale: 0.9 });
|
|
1909
|
+
gsap.set('.walkthrough-step', { opacity: 0, y: 20 });
|
|
1910
|
+
gsap.set('.terminal-line, .terminal-comment', { opacity: 0 });
|
|
1911
|
+
gsap.set('.json-line', { opacity: 0 });
|
|
1912
|
+
gsap.set('.install-step', { opacity: 0, y: 20 });
|
|
1913
|
+
gsap.set('.credit-link, .made-with', { opacity: 0 });
|
|
1914
|
+
gsap.set('.intro-text, .scroll-hint', { opacity: 0 });
|
|
1915
|
+
|
|
1916
|
+
document.querySelectorAll('.phase-box').forEach(box => {
|
|
1917
|
+
box.classList.remove('active');
|
|
1918
|
+
box.querySelector('.phase-status').textContent = '';
|
|
1919
|
+
});
|
|
1920
|
+
|
|
1921
|
+
ScrollTrigger.refresh();
|
|
1922
|
+
}, 500);
|
|
1923
|
+
});
|
|
1924
|
+
|
|
1925
|
+
// ============================================
|
|
1926
|
+
// HOVER EFFECTS
|
|
1927
|
+
// ============================================
|
|
1928
|
+
document.querySelectorAll('.phase-box, .gap-item, .solution-card, .hook-file').forEach(el => {
|
|
1929
|
+
el.addEventListener('mouseenter', () => {
|
|
1930
|
+
gsap.to(el, {
|
|
1931
|
+
boxShadow: '0 0 30px rgba(255,255,255,0.15)',
|
|
1932
|
+
duration: 0.3
|
|
1933
|
+
});
|
|
1934
|
+
});
|
|
1935
|
+
el.addEventListener('mouseleave', () => {
|
|
1936
|
+
gsap.to(el, {
|
|
1937
|
+
boxShadow: 'none',
|
|
1938
|
+
duration: 0.3
|
|
1939
|
+
});
|
|
1940
|
+
});
|
|
1941
|
+
});
|
|
1942
|
+
</script>
|
|
1943
|
+
|
|
1944
|
+
</body>
|
|
1945
|
+
</html>
|