@hustle-together/api-dev-tools 1.3.0 → 1.6.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.
@@ -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>