design-clone 1.0.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.
Files changed (47) hide show
  1. package/.env.example +14 -0
  2. package/LICENSE +21 -0
  3. package/README.md +166 -0
  4. package/SKILL.md +239 -0
  5. package/bin/cli.js +45 -0
  6. package/bin/commands/help.js +29 -0
  7. package/bin/commands/init.js +126 -0
  8. package/bin/commands/verify.js +99 -0
  9. package/bin/utils/copy.js +65 -0
  10. package/bin/utils/validate.js +122 -0
  11. package/docs/basic-clone.md +63 -0
  12. package/docs/cli-reference.md +94 -0
  13. package/docs/design-clone-architecture.md +247 -0
  14. package/docs/pixel-perfect.md +86 -0
  15. package/docs/troubleshooting.md +97 -0
  16. package/package.json +57 -0
  17. package/requirements.txt +5 -0
  18. package/src/ai/analyze-structure.py +305 -0
  19. package/src/ai/extract-design-tokens.py +439 -0
  20. package/src/ai/prompts/__init__.py +2 -0
  21. package/src/ai/prompts/design_tokens.py +183 -0
  22. package/src/ai/prompts/structure_analysis.py +273 -0
  23. package/src/core/cookie-handler.js +76 -0
  24. package/src/core/css-extractor.js +107 -0
  25. package/src/core/dimension-extractor.js +366 -0
  26. package/src/core/dimension-output.js +208 -0
  27. package/src/core/extract-assets.js +468 -0
  28. package/src/core/filter-css.js +499 -0
  29. package/src/core/html-extractor.js +102 -0
  30. package/src/core/lazy-loader.js +188 -0
  31. package/src/core/page-readiness.js +161 -0
  32. package/src/core/screenshot.js +380 -0
  33. package/src/post-process/enhance-assets.js +157 -0
  34. package/src/post-process/fetch-images.js +398 -0
  35. package/src/post-process/inject-icons.js +311 -0
  36. package/src/utils/__init__.py +16 -0
  37. package/src/utils/__pycache__/__init__.cpython-313.pyc +0 -0
  38. package/src/utils/__pycache__/env.cpython-313.pyc +0 -0
  39. package/src/utils/browser.js +103 -0
  40. package/src/utils/env.js +153 -0
  41. package/src/utils/env.py +134 -0
  42. package/src/utils/helpers.js +71 -0
  43. package/src/utils/puppeteer.js +281 -0
  44. package/src/verification/verify-layout.js +424 -0
  45. package/src/verification/verify-menu.js +422 -0
  46. package/templates/base.css +705 -0
  47. package/templates/base.html +293 -0
@@ -0,0 +1,705 @@
1
+ /**
2
+ * Base Styles - Design Clone Template
3
+ *
4
+ * Japanese Design Principles:
5
+ * - Ma (間) - Negative space, breathing room
6
+ * - Kanso (簡素) - Simplicity, elimination of clutter
7
+ * - Shibui (渋い) - Subtle, understated elegance
8
+ * - Seijaku (静寂) - Tranquility, calm atmosphere
9
+ *
10
+ * Uses CSS Variables from tokens.css
11
+ * Follows BEM naming convention
12
+ * Mobile-first responsive approach
13
+ */
14
+
15
+ /* ==========================================================================
16
+ Reset & Base
17
+ ========================================================================== */
18
+
19
+ *,
20
+ *::before,
21
+ *::after {
22
+ box-sizing: border-box;
23
+ margin: 0;
24
+ padding: 0;
25
+ }
26
+
27
+ html {
28
+ font-size: 16px;
29
+ scroll-behavior: smooth;
30
+ -webkit-font-smoothing: antialiased;
31
+ -moz-osx-font-smoothing: grayscale;
32
+ }
33
+
34
+ body {
35
+ font-family: var(--font-body);
36
+ font-size: var(--font-size-base);
37
+ font-weight: var(--font-weight-normal);
38
+ line-height: var(--line-height-normal);
39
+ color: var(--color-text-primary);
40
+ background-color: var(--color-background);
41
+ }
42
+
43
+ body.no-scroll {
44
+ overflow: hidden;
45
+ }
46
+
47
+ img,
48
+ picture,
49
+ video,
50
+ canvas,
51
+ svg {
52
+ display: block;
53
+ max-width: 100%;
54
+ }
55
+
56
+ img {
57
+ height: auto;
58
+ object-fit: cover;
59
+ }
60
+
61
+ /* ==========================================================================
62
+ Typography
63
+ ========================================================================== */
64
+
65
+ h1, h2, h3, h4, h5, h6 {
66
+ font-family: var(--font-heading);
67
+ font-weight: var(--font-weight-bold);
68
+ line-height: var(--line-height-tight);
69
+ color: var(--color-text-primary);
70
+ }
71
+
72
+ h1 { font-size: var(--font-size-3xl); }
73
+ h2 { font-size: var(--font-size-2xl); }
74
+ h3 { font-size: var(--font-size-xl); }
75
+ h4 { font-size: var(--font-size-lg); }
76
+
77
+ @media (min-width: 768px) {
78
+ h1 { font-size: var(--font-size-4xl); }
79
+ h2 { font-size: var(--font-size-3xl); }
80
+ h3 { font-size: var(--font-size-2xl); }
81
+ }
82
+
83
+ p {
84
+ margin-bottom: var(--space-4);
85
+ }
86
+
87
+ p:last-child {
88
+ margin-bottom: 0;
89
+ }
90
+
91
+ a {
92
+ color: var(--color-primary);
93
+ text-decoration: none;
94
+ transition: color 0.2s ease;
95
+ }
96
+
97
+ a:hover {
98
+ color: var(--color-accent);
99
+ }
100
+
101
+ ul, ol {
102
+ list-style: none;
103
+ }
104
+
105
+ /* ==========================================================================
106
+ Buttons - With Font Awesome Icons
107
+ ========================================================================== */
108
+
109
+ .btn {
110
+ display: inline-flex;
111
+ align-items: center;
112
+ justify-content: center;
113
+ gap: var(--space-2);
114
+ padding: var(--space-3) var(--space-6);
115
+ font-family: var(--font-body);
116
+ font-size: var(--font-size-sm);
117
+ font-weight: var(--font-weight-medium);
118
+ line-height: 1;
119
+ text-decoration: none;
120
+ border: 2px solid transparent;
121
+ border-radius: var(--radius-md);
122
+ cursor: pointer;
123
+ transition: all 0.2s ease;
124
+ white-space: nowrap;
125
+ }
126
+
127
+ .btn i {
128
+ font-size: 0.9em;
129
+ }
130
+
131
+ .btn--primary {
132
+ background-color: var(--color-primary);
133
+ color: #fff;
134
+ border-color: var(--color-primary);
135
+ }
136
+
137
+ .btn--primary:hover {
138
+ opacity: 0.9;
139
+ transform: translateY(-1px);
140
+ }
141
+
142
+ .btn--secondary {
143
+ background-color: transparent;
144
+ color: var(--color-primary);
145
+ border-color: var(--color-primary);
146
+ }
147
+
148
+ .btn--secondary:hover {
149
+ background-color: var(--color-primary);
150
+ color: #fff;
151
+ }
152
+
153
+ .btn--lg {
154
+ padding: var(--space-4) var(--space-8);
155
+ font-size: var(--font-size-base);
156
+ }
157
+
158
+ /* ==========================================================================
159
+ Header
160
+ ========================================================================== */
161
+
162
+ .header {
163
+ position: fixed;
164
+ top: 0;
165
+ left: 0;
166
+ right: 0;
167
+ z-index: 100;
168
+ background-color: var(--color-background);
169
+ border-bottom: 1px solid var(--color-border);
170
+ }
171
+
172
+ .header__container {
173
+ display: flex;
174
+ align-items: center;
175
+ justify-content: space-between;
176
+ max-width: 1200px;
177
+ height: 60px;
178
+ margin: 0 auto;
179
+ padding: 0 var(--space-4);
180
+ }
181
+
182
+ .header__logo {
183
+ display: flex;
184
+ align-items: center;
185
+ gap: var(--space-2);
186
+ font-family: var(--font-heading);
187
+ font-size: var(--font-size-lg);
188
+ font-weight: var(--font-weight-bold);
189
+ color: var(--color-text-primary);
190
+ }
191
+
192
+ .header__logo:hover {
193
+ color: var(--color-primary);
194
+ }
195
+
196
+ .header__logo-icon {
197
+ font-size: 1.25em;
198
+ color: var(--color-primary);
199
+ }
200
+
201
+ .header__nav {
202
+ display: none;
203
+ }
204
+
205
+ @media (min-width: 1024px) {
206
+ .header__nav {
207
+ display: block;
208
+ }
209
+ }
210
+
211
+ .nav__list {
212
+ display: flex;
213
+ gap: var(--space-6);
214
+ }
215
+
216
+ .nav__link {
217
+ color: var(--color-text-secondary);
218
+ font-weight: var(--font-weight-medium);
219
+ font-size: var(--font-size-sm);
220
+ transition: color 0.2s ease;
221
+ }
222
+
223
+ .nav__link:hover {
224
+ color: var(--color-primary);
225
+ }
226
+
227
+ .header__cta {
228
+ display: none;
229
+ }
230
+
231
+ @media (min-width: 1024px) {
232
+ .header__cta {
233
+ display: inline-flex;
234
+ }
235
+ }
236
+
237
+ .header__menu-toggle {
238
+ display: flex;
239
+ align-items: center;
240
+ justify-content: center;
241
+ width: 40px;
242
+ height: 40px;
243
+ background: none;
244
+ border: none;
245
+ cursor: pointer;
246
+ color: var(--color-text-primary);
247
+ font-size: var(--font-size-xl);
248
+ }
249
+
250
+ @media (min-width: 1024px) {
251
+ .header__menu-toggle {
252
+ display: none;
253
+ }
254
+ }
255
+
256
+ /* ==========================================================================
257
+ Mobile Navigation
258
+ ========================================================================== */
259
+
260
+ .mobile-nav {
261
+ position: fixed;
262
+ top: 60px;
263
+ left: 0;
264
+ right: 0;
265
+ bottom: 0;
266
+ background-color: var(--color-background);
267
+ z-index: 90;
268
+ padding: var(--space-6) var(--space-4);
269
+ transform: translateX(100%);
270
+ transition: transform 0.3s ease;
271
+ }
272
+
273
+ .mobile-nav.is-active {
274
+ transform: translateX(0);
275
+ }
276
+
277
+ .mobile-nav__list {
278
+ display: flex;
279
+ flex-direction: column;
280
+ gap: var(--space-1);
281
+ margin-bottom: var(--space-6);
282
+ }
283
+
284
+ .mobile-nav__link {
285
+ display: block;
286
+ padding: var(--space-4);
287
+ font-size: var(--font-size-lg);
288
+ font-weight: var(--font-weight-medium);
289
+ color: var(--color-text-primary);
290
+ border-bottom: 1px solid var(--color-border);
291
+ transition: color 0.2s ease;
292
+ }
293
+
294
+ .mobile-nav__link:hover {
295
+ color: var(--color-primary);
296
+ }
297
+
298
+ .mobile-nav__cta {
299
+ width: 100%;
300
+ }
301
+
302
+ /* ==========================================================================
303
+ Main Content
304
+ ========================================================================== */
305
+
306
+ .main {
307
+ padding-top: 60px; /* Header height */
308
+ }
309
+
310
+ /* ==========================================================================
311
+ Hero Section - Ma (negative space)
312
+ ========================================================================== */
313
+
314
+ .hero {
315
+ padding: var(--space-12) var(--space-4);
316
+ }
317
+
318
+ @media (min-width: 768px) {
319
+ .hero {
320
+ padding: var(--space-16) var(--space-4);
321
+ }
322
+ }
323
+
324
+ .hero__container {
325
+ display: grid;
326
+ grid-template-columns: 1fr;
327
+ gap: var(--space-8);
328
+ max-width: 1200px;
329
+ margin: 0 auto;
330
+ align-items: center;
331
+ }
332
+
333
+ @media (min-width: 768px) {
334
+ .hero__container {
335
+ grid-template-columns: 1fr 1fr;
336
+ gap: var(--space-12);
337
+ }
338
+ }
339
+
340
+ .hero__content {
341
+ text-align: center;
342
+ }
343
+
344
+ @media (min-width: 768px) {
345
+ .hero__content {
346
+ text-align: left;
347
+ }
348
+ }
349
+
350
+ .hero__title {
351
+ margin-bottom: var(--space-4);
352
+ }
353
+
354
+ .hero__subtitle {
355
+ max-width: 500px;
356
+ margin: 0 auto var(--space-8);
357
+ font-size: var(--font-size-lg);
358
+ color: var(--color-text-secondary);
359
+ line-height: var(--line-height-relaxed);
360
+ }
361
+
362
+ @media (min-width: 768px) {
363
+ .hero__subtitle {
364
+ margin-left: 0;
365
+ }
366
+ }
367
+
368
+ .hero__actions {
369
+ display: flex;
370
+ flex-wrap: wrap;
371
+ justify-content: center;
372
+ gap: var(--space-4);
373
+ }
374
+
375
+ @media (min-width: 768px) {
376
+ .hero__actions {
377
+ justify-content: flex-start;
378
+ }
379
+ }
380
+
381
+ .hero__image {
382
+ border-radius: var(--radius-lg);
383
+ overflow: hidden;
384
+ }
385
+
386
+ .hero__image img {
387
+ width: 100%;
388
+ aspect-ratio: 4/3;
389
+ }
390
+
391
+ /* ==========================================================================
392
+ Features Section - Kanso (simplicity)
393
+ ========================================================================== */
394
+
395
+ .features {
396
+ padding: var(--space-16) var(--space-4);
397
+ background-color: var(--color-surface);
398
+ }
399
+
400
+ .features__container {
401
+ max-width: 1200px;
402
+ margin: 0 auto;
403
+ }
404
+
405
+ .features__title {
406
+ text-align: center;
407
+ margin-bottom: var(--space-2);
408
+ }
409
+
410
+ .features__subtitle {
411
+ text-align: center;
412
+ color: var(--color-text-secondary);
413
+ margin-bottom: var(--space-12);
414
+ }
415
+
416
+ .features__grid {
417
+ display: grid;
418
+ grid-template-columns: 1fr;
419
+ gap: var(--space-6);
420
+ }
421
+
422
+ @media (min-width: 768px) {
423
+ .features__grid {
424
+ grid-template-columns: repeat(3, 1fr);
425
+ gap: var(--space-8);
426
+ }
427
+ }
428
+
429
+ .feature-card {
430
+ padding: var(--space-8);
431
+ background-color: var(--color-background);
432
+ border-radius: var(--radius-lg);
433
+ box-shadow: var(--shadow-sm);
434
+ text-align: center;
435
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
436
+ }
437
+
438
+ .feature-card:hover {
439
+ transform: translateY(-4px);
440
+ box-shadow: var(--shadow-md);
441
+ }
442
+
443
+ .feature-card__icon {
444
+ display: inline-flex;
445
+ align-items: center;
446
+ justify-content: center;
447
+ width: 64px;
448
+ height: 64px;
449
+ margin-bottom: var(--space-4);
450
+ color: var(--color-primary);
451
+ font-size: 2rem;
452
+ }
453
+
454
+ .feature-card__title {
455
+ margin-bottom: var(--space-3);
456
+ }
457
+
458
+ .feature-card__description {
459
+ color: var(--color-text-secondary);
460
+ font-size: var(--font-size-sm);
461
+ line-height: var(--line-height-relaxed);
462
+ }
463
+
464
+ /* ==========================================================================
465
+ About Section - Shibui (understated elegance)
466
+ ========================================================================== */
467
+
468
+ .about {
469
+ padding: var(--space-16) var(--space-4);
470
+ }
471
+
472
+ .about__container {
473
+ display: grid;
474
+ grid-template-columns: 1fr;
475
+ gap: var(--space-8);
476
+ max-width: 1200px;
477
+ margin: 0 auto;
478
+ align-items: center;
479
+ }
480
+
481
+ @media (min-width: 768px) {
482
+ .about__container {
483
+ grid-template-columns: 1fr 1fr;
484
+ gap: var(--space-12);
485
+ }
486
+ }
487
+
488
+ .about__title {
489
+ margin-bottom: var(--space-4);
490
+ }
491
+
492
+ .about__text {
493
+ color: var(--color-text-secondary);
494
+ margin-bottom: var(--space-6);
495
+ line-height: var(--line-height-relaxed);
496
+ }
497
+
498
+ .about__image {
499
+ border-radius: var(--radius-lg);
500
+ overflow: hidden;
501
+ }
502
+
503
+ .about__image img {
504
+ width: 100%;
505
+ aspect-ratio: 4/3;
506
+ }
507
+
508
+ /* ==========================================================================
509
+ CTA Section - Seijaku (tranquility)
510
+ ========================================================================== */
511
+
512
+ .cta-section {
513
+ padding: var(--space-16) var(--space-4);
514
+ background-color: var(--color-primary);
515
+ color: #fff;
516
+ text-align: center;
517
+ }
518
+
519
+ .cta-section__container {
520
+ max-width: 700px;
521
+ margin: 0 auto;
522
+ }
523
+
524
+ .cta-section__title {
525
+ color: #fff;
526
+ margin-bottom: var(--space-3);
527
+ }
528
+
529
+ .cta-section__subtitle {
530
+ opacity: 0.9;
531
+ margin-bottom: var(--space-8);
532
+ font-size: var(--font-size-lg);
533
+ }
534
+
535
+ .cta-section__button {
536
+ background-color: #fff;
537
+ color: var(--color-primary);
538
+ border-color: #fff;
539
+ }
540
+
541
+ .cta-section__button:hover {
542
+ opacity: 0.95;
543
+ background-color: #fff;
544
+ color: var(--color-primary);
545
+ }
546
+
547
+ /* ==========================================================================
548
+ Footer
549
+ ========================================================================== */
550
+
551
+ .footer {
552
+ padding: var(--space-12) var(--space-4) var(--space-6);
553
+ background-color: #1a1a1a;
554
+ color: #fff;
555
+ }
556
+
557
+ .footer__container {
558
+ max-width: 1200px;
559
+ margin: 0 auto;
560
+ }
561
+
562
+ .footer__grid {
563
+ display: grid;
564
+ grid-template-columns: 1fr;
565
+ gap: var(--space-8);
566
+ margin-bottom: var(--space-8);
567
+ }
568
+
569
+ @media (min-width: 768px) {
570
+ .footer__grid {
571
+ grid-template-columns: 2fr 1fr 1fr 1fr;
572
+ gap: var(--space-12);
573
+ }
574
+ }
575
+
576
+ .footer__logo {
577
+ display: inline-flex;
578
+ align-items: center;
579
+ gap: var(--space-2);
580
+ font-family: var(--font-heading);
581
+ font-size: var(--font-size-xl);
582
+ font-weight: var(--font-weight-bold);
583
+ color: #fff;
584
+ margin-bottom: var(--space-4);
585
+ }
586
+
587
+ .footer__logo:hover {
588
+ color: var(--color-secondary);
589
+ }
590
+
591
+ .footer__logo i {
592
+ color: var(--color-primary);
593
+ }
594
+
595
+ .footer__tagline {
596
+ color: rgba(255, 255, 255, 0.7);
597
+ font-size: var(--font-size-sm);
598
+ margin-bottom: var(--space-4);
599
+ line-height: var(--line-height-relaxed);
600
+ }
601
+
602
+ .footer__social {
603
+ display: flex;
604
+ gap: var(--space-3);
605
+ }
606
+
607
+ .footer__social-link {
608
+ display: flex;
609
+ align-items: center;
610
+ justify-content: center;
611
+ width: 36px;
612
+ height: 36px;
613
+ color: rgba(255, 255, 255, 0.7);
614
+ font-size: var(--font-size-lg);
615
+ border-radius: var(--radius-full);
616
+ transition: color 0.2s ease, background-color 0.2s ease;
617
+ }
618
+
619
+ .footer__social-link:hover {
620
+ color: #fff;
621
+ background-color: rgba(255, 255, 255, 0.1);
622
+ }
623
+
624
+ .footer__heading {
625
+ font-size: var(--font-size-sm);
626
+ font-weight: var(--font-weight-semibold);
627
+ text-transform: uppercase;
628
+ letter-spacing: 0.05em;
629
+ color: #fff;
630
+ margin-bottom: var(--space-4);
631
+ }
632
+
633
+ .footer__links li {
634
+ margin-bottom: var(--space-2);
635
+ }
636
+
637
+ .footer__link {
638
+ color: rgba(255, 255, 255, 0.7);
639
+ font-size: var(--font-size-sm);
640
+ transition: color 0.2s ease;
641
+ }
642
+
643
+ .footer__link:hover {
644
+ color: #fff;
645
+ }
646
+
647
+ .footer__bottom {
648
+ padding-top: var(--space-6);
649
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
650
+ text-align: center;
651
+ }
652
+
653
+ .footer__copyright {
654
+ color: rgba(255, 255, 255, 0.5);
655
+ font-size: var(--font-size-xs);
656
+ }
657
+
658
+ /* ==========================================================================
659
+ Utilities
660
+ ========================================================================== */
661
+
662
+ .container {
663
+ width: 100%;
664
+ max-width: 1200px;
665
+ margin: 0 auto;
666
+ padding: 0 var(--space-4);
667
+ }
668
+
669
+ .visually-hidden {
670
+ position: absolute;
671
+ width: 1px;
672
+ height: 1px;
673
+ padding: 0;
674
+ margin: -1px;
675
+ overflow: hidden;
676
+ clip: rect(0, 0, 0, 0);
677
+ white-space: nowrap;
678
+ border: 0;
679
+ }
680
+
681
+ /* ==========================================================================
682
+ Print Styles
683
+ ========================================================================== */
684
+
685
+ @media print {
686
+ .header,
687
+ .footer__social,
688
+ .btn,
689
+ .mobile-nav {
690
+ display: none;
691
+ }
692
+
693
+ body {
694
+ font-size: 12pt;
695
+ line-height: 1.5;
696
+ }
697
+
698
+ a {
699
+ text-decoration: underline;
700
+ }
701
+
702
+ a[href]::after {
703
+ content: " (" attr(href) ")";
704
+ }
705
+ }