@yojahny/wp-design-library 0.5.1 → 0.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.
Files changed (130) hide show
  1. package/bin/library.mjs +1 -0
  2. package/entries/ada/entry.md +24 -6
  3. package/entries/air/entry.md +39 -10
  4. package/entries/ais-community-dark-depth/entry.md +44 -19
  5. package/entries/apple-home/entry.md +43 -10
  6. package/entries/apple-macbook-neo/entry.md +39 -10
  7. package/entries/apple-watch-ultra-4/entry.md +36 -11
  8. package/entries/bpco/entry.md +15 -7
  9. package/entries/column/entry.md +22 -9
  10. package/entries/cthdrl/entry.md +41 -19
  11. package/entries/dala-craftedbygc/entry.md +41 -16
  12. package/entries/dock/entry.md +36 -10
  13. package/entries/dub/entry.md +35 -10
  14. package/entries/duolingo/entry.md +42 -10
  15. package/entries/elevenlabs/entry.md +42 -10
  16. package/entries/flying-papers/entry.md +32 -10
  17. package/entries/gsap/entry.md +40 -10
  18. package/entries/letters/entry.md +40 -10
  19. package/entries/micro/entry.md +34 -10
  20. package/entries/monopo-saigon/entry.md +41 -12
  21. package/entries/notion/entry.md +42 -10
  22. package/entries/origin-financial/entry.md +42 -9
  23. package/entries/oryzo-ai/entry.md +46 -11
  24. package/entries/silencio/entry.md +6 -2
  25. package/entries/steep/entry.md +38 -12
  26. package/entries/stripe/entry.md +34 -10
  27. package/entries/superpower/entry.md +43 -9
  28. package/entries/superr/entry.md +22 -6
  29. package/entries/svz-weare/entry.md +15 -5
  30. package/entries/thoughtlab/entry.md +42 -10
  31. package/entries/ventriloc/entry.md +22 -6
  32. package/entries/vivid-and-co/entry.md +30 -5
  33. package/package.json +4 -1
  34. package/src/artifacts.mjs +31 -0
  35. package/src/cli/add.mjs +55 -24
  36. package/src/cli/index.mjs +1 -1
  37. package/src/cli/migrate-artifacts.mjs +92 -0
  38. package/src/cli/motion.mjs +19 -39
  39. package/src/cli/refresh.mjs +40 -10
  40. package/src/cli/save.mjs +1 -1
  41. package/src/cli/serve.mjs +27 -7
  42. package/src/cli/ui.mjs +1 -1
  43. package/src/entry.mjs +15 -11
  44. package/src/index/build.mjs +13 -3
  45. package/src/ingest/agreement.mjs +14 -1
  46. package/src/ingest/attach.mjs +8 -15
  47. package/src/ingest/save.mjs +2 -2
  48. package/src/mcp/tools.mjs +29 -17
  49. package/src/r2.mjs +95 -0
  50. package/src/ui/build.mjs +30 -12
  51. package/src/ui/templates/index.html +2 -0
  52. package/entries/ada/strip.webp +0 -0
  53. package/entries/air/captures/2/measure.json +0 -325
  54. package/entries/air/captures/2/strip.webp +0 -0
  55. package/entries/air/strip.webp +0 -0
  56. package/entries/ais-community-dark-depth/strip.webp +0 -0
  57. package/entries/apple-home/captures/2/measure.json +0 -91
  58. package/entries/apple-home/captures/2/strip.webp +0 -0
  59. package/entries/apple-home/strip.webp +0 -0
  60. package/entries/apple-macbook-neo/captures/2/measure.json +0 -570
  61. package/entries/apple-macbook-neo/captures/2/strip.webp +0 -0
  62. package/entries/apple-macbook-neo/strip.webp +0 -0
  63. package/entries/apple-watch-ultra-4/measure.json +0 -481
  64. package/entries/apple-watch-ultra-4/strip.webp +0 -0
  65. package/entries/bpco/captures/2/strip.webp +0 -0
  66. package/entries/bpco/captures/3/strip.webp +0 -0
  67. package/entries/bpco/strip.webp +0 -0
  68. package/entries/column/captures/2/measure.json +0 -996
  69. package/entries/column/captures/2/strip.webp +0 -0
  70. package/entries/column/strip.webp +0 -0
  71. package/entries/cthdrl/captures/2/measure.json +0 -251
  72. package/entries/cthdrl/captures/2/strip.webp +0 -0
  73. package/entries/cthdrl/strip.webp +0 -0
  74. package/entries/dala-craftedbygc/strip.webp +0 -0
  75. package/entries/dock/captures/2/measure.json +0 -206
  76. package/entries/dock/captures/2/strip.webp +0 -0
  77. package/entries/dock/strip.webp +0 -0
  78. package/entries/dub/captures/2/measure.json +0 -37
  79. package/entries/dub/captures/2/strip.webp +0 -0
  80. package/entries/dub/strip.webp +0 -0
  81. package/entries/duolingo/captures/2/measure.json +0 -138
  82. package/entries/duolingo/captures/2/strip.webp +0 -0
  83. package/entries/duolingo/strip.webp +0 -0
  84. package/entries/elevenlabs/captures/2/measure.json +0 -160
  85. package/entries/elevenlabs/captures/2/strip.webp +0 -0
  86. package/entries/elevenlabs/strip.webp +0 -0
  87. package/entries/flying-papers/captures/2/measure.json +0 -291
  88. package/entries/flying-papers/captures/2/strip.webp +0 -0
  89. package/entries/flying-papers/strip.webp +0 -0
  90. package/entries/gsap/captures/2/measure.json +0 -120
  91. package/entries/gsap/captures/2/strip.webp +0 -0
  92. package/entries/gsap/strip.webp +0 -0
  93. package/entries/letters/captures/2/measure.json +0 -20
  94. package/entries/letters/captures/2/strip.webp +0 -0
  95. package/entries/letters/strip.webp +0 -0
  96. package/entries/micro/captures/2/measure.json +0 -852
  97. package/entries/micro/captures/2/strip.webp +0 -0
  98. package/entries/micro/strip.webp +0 -0
  99. package/entries/monopo-saigon/captures/2/measure.json +0 -145
  100. package/entries/monopo-saigon/captures/2/strip.webp +0 -0
  101. package/entries/monopo-saigon/strip.webp +0 -0
  102. package/entries/notion/captures/2/measure.json +0 -338
  103. package/entries/notion/captures/2/strip.webp +0 -0
  104. package/entries/notion/strip.webp +0 -0
  105. package/entries/origin-financial/captures/2/measure.json +0 -169
  106. package/entries/origin-financial/captures/2/strip.webp +0 -0
  107. package/entries/origin-financial/strip.webp +0 -0
  108. package/entries/oryzo-ai/captures/2/measure.json +0 -39
  109. package/entries/oryzo-ai/captures/2/strip.webp +0 -0
  110. package/entries/oryzo-ai/strip.webp +0 -0
  111. package/entries/silencio/captures/2/strip.webp +0 -0
  112. package/entries/silencio/strip.webp +0 -0
  113. package/entries/steep/captures/2/measure.json +0 -20
  114. package/entries/steep/captures/2/strip.webp +0 -0
  115. package/entries/steep/strip.webp +0 -0
  116. package/entries/stripe/captures/2/measure.json +0 -892
  117. package/entries/stripe/captures/2/strip.webp +0 -0
  118. package/entries/stripe/strip.webp +0 -0
  119. package/entries/superpower/captures/2/measure.json +0 -179
  120. package/entries/superpower/captures/2/strip.webp +0 -0
  121. package/entries/superpower/strip.webp +0 -0
  122. package/entries/superr/strip.webp +0 -0
  123. package/entries/svz-weare/captures/2/measure.json +0 -129
  124. package/entries/svz-weare/captures/2/strip.webp +0 -0
  125. package/entries/svz-weare/strip.webp +0 -0
  126. package/entries/thoughtlab/captures/2/measure.json +0 -93
  127. package/entries/thoughtlab/captures/2/strip.webp +0 -0
  128. package/entries/thoughtlab/strip.webp +0 -0
  129. package/entries/ventriloc/strip.webp +0 -0
  130. package/entries/vivid-and-co/strip.webp +0 -0
package/src/ui/build.mjs CHANGED
@@ -5,6 +5,7 @@ import sharp from 'sharp';
5
5
  import { listEntries, parseEntry, validateEntry } from '../entry.mjs';
6
6
  import { loadVocab, FACETS } from '../vocab.mjs';
7
7
  import { validateMotion, motionImagePath, localMotionPath } from '../motion.mjs';
8
+ import { artifactFile } from '../artifacts.mjs';
8
9
 
9
10
  const DIR = path.dirname(fileURLToPath(import.meta.url));
10
11
  const TPL = path.join(DIR, 'templates');
@@ -53,10 +54,13 @@ function card(row) {
53
54
  `${img}<div class="meta"><strong>${esc(row.title)}</strong>${badge}<br><small>${esc(row.tier)} &middot; ${tags}</small></div></a>`;
54
55
  }
55
56
 
56
- // measure.json is only written for a live-URL capture (`add <url>`/`refresh`); frame-sampled entries have none.
57
- function measurementsHtml(dir) {
58
- const file = path.join(dir, 'measure.json');
59
- if (!fs.existsSync(file)) return '';
57
+ // measure.json is only written for a live-URL capture (`add <url>`/`refresh`); frame-sampled
58
+ // entries have none. `file` is already resolved through the artifact cache by the caller, or null
59
+ // when there is no record or the object could not be fetched — the same degradation the strip
60
+ // applies. It was read straight off the entry directory, which the migration empties, and which
61
+ // never looked under captures/<n>/ anyway.
62
+ function measurementsHtml(file) {
63
+ if (!file) return '';
60
64
  const m = JSON.parse(fs.readFileSync(file, 'utf8'));
61
65
  const t = m.tokens ?? {};
62
66
  return `<h2>Measured tokens</h2><dl><dt>Canvas</dt><dd>${esc(t.canvas)}</dd><dt>Ink</dt><dd>${esc(t.ink)}</dd><dt>Accent</dt><dd>${esc(t.accent)}</dd></dl>` +
@@ -124,14 +128,14 @@ function motionHtml(outDir, entry, previewMediaDir) {
124
128
  return `<section aria-label="Motion previews"><h2>Motion previews</h2>${figures.join('\n')}</section>`;
125
129
  }
126
130
 
127
- function writeEntryPage(outDir, entry, row, previewMediaDir) {
131
+ function writeEntryPage(outDir, entry, row, previewMediaDir, measureFile) {
128
132
  const tpl = fs.readFileSync(path.join(TPL, 'entry.html'), 'utf8');
129
133
  const html = render(tpl, {
130
134
  TITLE: esc(row.title), TIER: esc(row.tier), ROLES: esc(row.roles.join(', ')), FEEL: esc(row.feel.join(', ')),
131
135
  MOTION: esc(row.motion.join(', ')), SOURCE: esc(row.source), LICENSE: esc(entry.fm.source?.license),
132
136
  CAPTURED: esc(row.captured), STRIP_IMG: row.strip ? `<img src="../${row.strip}" alt="">` : '',
133
137
  DRAFT_BADGE: row.draft ? '<span class="badge">draft</span>' : '', BODY: mdToHtml(entry.body),
134
- MEASUREMENTS: measurementsHtml(entry.dir),
138
+ MEASUREMENTS: measurementsHtml(measureFile),
135
139
  MOTION_CLIPS: motionHtml(outDir, entry, previewMediaDir),
136
140
  SITE_ROW: fieldRow('Site', linkify(entry.fm.source?.url)),
137
141
  CAPTURES_ROW: fieldRow('Captures', (entry.fm.captured?.captures ?? [])
@@ -143,7 +147,7 @@ function writeEntryPage(outDir, entry, row, previewMediaDir) {
143
147
  // `indexPath` is accepted for interface symmetry with buildIndex but unused: a draft is an
144
148
  // entry that fails validateEntry, and buildIndex never puts a failing entry in the sqlite
145
149
  // index — so entries/ is the one place both valid and draft entries can be read from.
146
- export async function buildUi({ indexPath, entriesDir, outDir, previewMediaDir }) {
150
+ export async function buildUi({ indexPath, entriesDir, outDir, previewMediaDir, p }) {
147
151
  void indexPath;
148
152
  const vocab = loadVocab();
149
153
  fs.rmSync(outDir, { recursive: true, force: true });
@@ -161,8 +165,16 @@ export async function buildUi({ indexPath, entriesDir, outDir, previewMediaDir }
161
165
  // slug === dir name, so fm.slug can carry path-traversal or markup and must never
162
166
  // reach a path or an unescaped attribute.
163
167
  const slug = path.basename(dir);
164
- const stripSrc = path.join(dir, 'strip.webp');
165
- const hasStrip = fs.existsSync(stripSrc);
168
+ let stripSrc = null;
169
+ const strip = (entry.fm.captured?.captures?.[0]?.artifacts ?? []).find((a) => a?.key?.endsWith('/strip.webp'));
170
+ // One unreachable object must not take the gallery down with it: the entry renders without a
171
+ // thumbnail, exactly as a draft does, and the build continues.
172
+ if (strip) { try { stripSrc = await artifactFile(p, strip); } catch { stripSrc = null; } }
173
+ // Same treatment for measure.json: a record to resolve, never a file next to entry.md.
174
+ let measureSrc = null;
175
+ const measured = (entry.fm.captured?.captures?.[0]?.artifacts ?? []).find((a) => a?.key?.endsWith('/measure.json'));
176
+ if (measured) { try { measureSrc = await artifactFile(p, measured); } catch { measureSrc = null; } }
177
+ const hasStrip = stripSrc !== null;
166
178
  if (hasStrip) {
167
179
  fs.copyFileSync(stripSrc, path.join(outDir, 'strips', `${slug}.webp`));
168
180
  // The index is a browsing surface. Its previews must not make each visitor
@@ -183,16 +195,22 @@ export async function buildUi({ indexPath, entriesDir, outDir, previewMediaDir }
183
195
  draft: !ok,
184
196
  };
185
197
  rows.push(row);
186
- writeEntryPage(outDir, entry, row, previewMediaDir);
198
+ writeEntryPage(outDir, entry, row, previewMediaDir, measureSrc);
187
199
  }
188
200
  rows.sort((a, b) => b.captured.localeCompare(a.captured));
189
201
 
190
202
  fs.writeFileSync(path.join(outDir, 'manifest.json'), JSON.stringify(rows, null, 2));
191
203
  const tpl = fs.readFileSync(path.join(TPL, 'index.html'), 'utf8');
192
204
  const filters = FACETS.map((f) => filterFieldset(f, vocab.facets[f])).join('\n');
193
- fs.writeFileSync(path.join(outDir, 'index.html'), render(tpl, { FILTERS: filters, GRID: rows.map(card).join('\n') }));
205
+ const drafts = rows.filter((r) => r.draft).length;
206
+ // Rendered server-side, not left to the client-side draft filter: a build where every
207
+ // entry failed validation must say so even before app.js runs, or the visitor sees an
208
+ // unexplained blank grid (the incident this guards against).
209
+ const notice = rows.length > 0 && drafts === rows.length
210
+ ? `<p id="empty-state">${rows.length} ${rows.length === 1 ? 'entry' : 'entries'} in the library, all hidden because they failed validation. Check &quot;Show drafts&quot; above to view them.</p>`
211
+ : '';
212
+ fs.writeFileSync(path.join(outDir, 'index.html'), render(tpl, { FILTERS: filters, GRID: rows.map(card).join('\n'), NOTICE: notice }));
194
213
  fs.copyFileSync(path.join(DIR, 'app.js'), path.join(outDir, 'app.js'));
195
214
 
196
- const drafts = rows.filter((r) => r.draft).length;
197
215
  return { entries: rows.length - drafts, drafts };
198
216
  }
@@ -15,6 +15,7 @@
15
15
  .card .ph { width: 100%; aspect-ratio: 4/3; background: #8882; }
16
16
  .card .meta { padding: .5rem; }
17
17
  .badge { background: #d33; color: #fff; font-size: .7em; padding: .1em .4em; border-radius: 4px; }
18
+ #empty-state { padding: .75rem 1rem; border: 1px solid #d33; border-radius: 8px; margin-bottom: 1rem; }
18
19
  [hidden] { display: none !important; }
19
20
  </style>
20
21
  </head>
@@ -24,6 +25,7 @@
24
25
  {{FILTERS}}
25
26
  <label><input type="checkbox" id="drafts-toggle"> Show drafts</label>
26
27
  </form>
28
+ {{NOTICE}}
27
29
  <div id="grid">
28
30
  {{GRID}}
29
31
  </div>
Binary file
@@ -1,325 +0,0 @@
1
- {
2
- "url": "https://air.inc/",
3
- "at": "2026-09-17",
4
- "viewport": [
5
- 1440,
6
- 390
7
- ],
8
- "tokens": {
9
- "canvas": "#13396a",
10
- "ink": "#000000",
11
- "accent": "#1b1b1b",
12
- "fontDisplay": "\"Control Compressed\", Arial, Helvetica, sans-serif",
13
- "fontBody": "Control, Arial, Helvetica, sans-serif"
14
- },
15
- "sections": [
16
- {
17
- "index": 0,
18
- "tag": "header",
19
- "id": "",
20
- "class": "Header_root__hagAA",
21
- "top": 0,
22
- "height": 72,
23
- "animations": []
24
- },
25
- {
26
- "index": 1,
27
- "tag": "div",
28
- "id": "",
29
- "class": "canvas canvas___loaded",
30
- "top": 0,
31
- "height": 900,
32
- "animations": []
33
- },
34
- {
35
- "index": 2,
36
- "tag": "section",
37
- "id": "Hero",
38
- "class": "Section_root__XZMWH p-0! Section_root___spacingDefault__lCxmv",
39
- "top": 0,
40
- "height": 1020,
41
- "animations": []
42
- },
43
- {
44
- "index": 3,
45
- "tag": "section",
46
- "id": "Agentic Cards",
47
- "class": "Section_root__XZMWH p-0! Section_root___spacingDefault__lCxmv bg-center bg-contain bg-no-repeat",
48
- "top": 1020,
49
- "height": 1021,
50
- "animations": []
51
- },
52
- {
53
- "index": 4,
54
- "tag": "section",
55
- "id": "",
56
- "class": "flex w-full flex-col gap-12",
57
- "top": 1282,
58
- "height": 631,
59
- "animations": []
60
- },
61
- {
62
- "index": 5,
63
- "tag": "section",
64
- "id": "Logos",
65
- "class": "Section_root__XZMWH Section_root___spacingSmall__u_8bU",
66
- "top": 2041,
67
- "height": 502,
68
- "animations": []
69
- },
70
- {
71
- "index": 6,
72
- "tag": "section",
73
- "id": "agent-waitlist",
74
- "class": "Section_root__XZMWH p-0! Section_root___spacingDefault__lCxmv bg-center bg- bg-no-repeat",
75
- "top": 2543,
76
- "height": 858,
77
- "animations": [
78
- {
79
- "target": "div.AnimatedBorder_root_stroke__5hoiG",
80
- "timeline": "document",
81
- "range": null,
82
- "duration": 10000
83
- },
84
- {
85
- "target": "div.AnimatedBorder_root_stroke__5hoiG",
86
- "timeline": "document",
87
- "range": null,
88
- "duration": 10000
89
- }
90
- ]
91
- },
92
- {
93
- "index": 7,
94
- "tag": "section",
95
- "id": "Spacing",
96
- "class": "Section_root__XZMWH Section_root___spacingDefault__lCxmv bg-center bg-contain bg-no-repeat",
97
- "top": 3401,
98
- "height": 240,
99
- "animations": []
100
- },
101
- {
102
- "index": 8,
103
- "tag": "section",
104
- "id": "Supersize Text",
105
- "class": "Section_root__XZMWH Section_root___spacingDefault__lCxmv",
106
- "top": 3641,
107
- "height": 949,
108
- "animations": []
109
- },
110
- {
111
- "index": 9,
112
- "tag": "section",
113
- "id": "Primary Product Demo",
114
- "class": "Section_root__XZMWH p-0! Section_root___spacingDefault__lCxmv",
115
- "top": 4590,
116
- "height": 638,
117
- "animations": []
118
- },
119
- {
120
- "index": 10,
121
- "tag": "section",
122
- "id": "Features",
123
- "class": "Section_root__XZMWH p-0! Section_root___spacingLarge__acfRQ",
124
- "top": 5228,
125
- "height": 1416,
126
- "animations": [
127
- {
128
- "target": "div.AnimatedBorder_root_stroke__5hoiG",
129
- "timeline": "document",
130
- "range": null,
131
- "duration": 10000
132
- },
133
- {
134
- "target": "div.AnimatedBorder_root_stroke__5hoiG",
135
- "timeline": "document",
136
- "range": null,
137
- "duration": 10000
138
- },
139
- {
140
- "target": "div.AnimatedBorder_root_stroke__5hoiG",
141
- "timeline": "document",
142
- "range": null,
143
- "duration": 10000
144
- },
145
- {
146
- "target": "div.AnimatedBorder_root_stroke__5hoiG",
147
- "timeline": "document",
148
- "range": null,
149
- "duration": 10000
150
- },
151
- {
152
- "target": "div.AnimatedBorder_root_stroke__5hoiG",
153
- "timeline": "document",
154
- "range": null,
155
- "duration": 10000
156
- },
157
- {
158
- "target": "div.AnimatedBorder_root_stroke__5hoiG",
159
- "timeline": "document",
160
- "range": null,
161
- "duration": 10000
162
- },
163
- {
164
- "target": "div.AnimatedBorder_root_stroke__5hoiG",
165
- "timeline": "document",
166
- "range": null,
167
- "duration": 10000
168
- }
169
- ]
170
- },
171
- {
172
- "index": 11,
173
- "tag": "section",
174
- "id": "Models",
175
- "class": "Section_root__XZMWH p-0! Section_root___spacingDefault__lCxmv bg-center bg-contain bg-no-repeat",
176
- "top": 6645,
177
- "height": 256,
178
- "animations": [
179
- {
180
- "target": "div.CTACard_root_orbs_inner__sJJHM",
181
- "timeline": "document",
182
- "range": null,
183
- "duration": 10000
184
- },
185
- {
186
- "target": "div.CTACard_root_orbs_item__ocG9A",
187
- "timeline": "document",
188
- "range": null,
189
- "duration": 6000
190
- },
191
- {
192
- "target": "div.CTACard_root_orbs_item__ocG9A",
193
- "timeline": "document",
194
- "range": null,
195
- "duration": 6000
196
- },
197
- {
198
- "target": "div.CTACard_root_orbs_item__ocG9A",
199
- "timeline": "document",
200
- "range": null,
201
- "duration": 6000
202
- },
203
- {
204
- "target": "div.AnimatedBorder_root_stroke__5hoiG",
205
- "timeline": "document",
206
- "range": null,
207
- "duration": 10000
208
- }
209
- ]
210
- },
211
- {
212
- "index": 12,
213
- "tag": "section",
214
- "id": "Integrations",
215
- "class": "Section_root__XZMWH Section_root___headerPadding__9L15p Section_root___spacingSmall__u_8bU bg-center bg-contain bg-no-repeat",
216
- "top": 6901,
217
- "height": 439,
218
- "animations": []
219
- },
220
- {
221
- "index": 13,
222
- "tag": "section",
223
- "id": "Storytelling",
224
- "class": "Section_root__XZMWH Section_root___spacingDefault__lCxmv bg-center bg-contain bg-no-repeat",
225
- "top": 7340,
226
- "height": 3888,
227
- "animations": []
228
- },
229
- {
230
- "index": 14,
231
- "tag": "section",
232
- "id": "Book a Demo Form",
233
- "class": "Section_root__XZMWH Section_root___spacingDefault__lCxmv",
234
- "top": 11228,
235
- "height": 1162,
236
- "animations": [
237
- {
238
- "target": "h1.u-h2-large",
239
- "timeline": "document",
240
- "range": null,
241
- "duration": 1000
242
- },
243
- {
244
- "target": "h1.u-h2-large",
245
- "timeline": "document",
246
- "range": null,
247
- "duration": 1000
248
- },
249
- {
250
- "target": "span",
251
- "timeline": "document",
252
- "range": null,
253
- "duration": 1000
254
- },
255
- {
256
- "target": "span",
257
- "timeline": "document",
258
- "range": null,
259
- "duration": 1000
260
- },
261
- {
262
- "target": "span",
263
- "timeline": "document",
264
- "range": null,
265
- "duration": 1000
266
- },
267
- {
268
- "target": "span",
269
- "timeline": "document",
270
- "range": null,
271
- "duration": 1000
272
- },
273
- {
274
- "target": "span",
275
- "timeline": "document",
276
- "range": null,
277
- "duration": 1000
278
- },
279
- {
280
- "target": "span",
281
- "timeline": "document",
282
- "range": null,
283
- "duration": 1000
284
- },
285
- {
286
- "target": "span",
287
- "timeline": "document",
288
- "range": null,
289
- "duration": 1000
290
- },
291
- {
292
- "target": "span",
293
- "timeline": "document",
294
- "range": null,
295
- "duration": 1000
296
- },
297
- {
298
- "target": "p",
299
- "timeline": "document",
300
- "range": null,
301
- "duration": 1000
302
- },
303
- {
304
- "target": "p",
305
- "timeline": "document",
306
- "range": null,
307
- "duration": 1000
308
- }
309
- ]
310
- },
311
- {
312
- "index": 15,
313
- "tag": "footer",
314
- "id": "Footer",
315
- "class": "Section_root__XZMWH p-0! Footer_root__g9BuT",
316
- "top": 12390,
317
- "height": 1350,
318
- "animations": []
319
- }
320
- ],
321
- "screenshots": {
322
- "390": "screen-390.png",
323
- "1440": "screen-1440.png"
324
- }
325
- }
Binary file
Binary file
@@ -1,91 +0,0 @@
1
- {
2
- "url": "https://www.apple.com/",
3
- "at": "2026-09-16",
4
- "viewport": [
5
- 1440,
6
- 390
7
- ],
8
- "tokens": {
9
- "canvas": "#ffffff",
10
- "ink": "#1d1d1f",
11
- "accent": "#333336",
12
- "fontDisplay": "\"SF Pro Text\", \"SF Pro Icons\", \"Helvetica Neue\", Helvetica, Arial, sans-serif",
13
- "fontBody": "\"SF Pro Display\", \"SF Pro Icons\", \"Helvetica Neue\", Helvetica, Arial, sans-serif"
14
- },
15
- "sections": [
16
- {
17
- "index": 0,
18
- "tag": "section",
19
- "id": "",
20
- "class": "section-ribbon",
21
- "top": 44,
22
- "height": 52,
23
- "animations": []
24
- },
25
- {
26
- "index": 1,
27
- "tag": "section",
28
- "id": "",
29
- "class": "section section-hero",
30
- "top": 96,
31
- "height": 2100,
32
- "animations": []
33
- },
34
- {
35
- "index": 2,
36
- "tag": "section",
37
- "id": "",
38
- "class": "section section-promo",
39
- "top": 2208,
40
- "height": 1764,
41
- "animations": []
42
- },
43
- {
44
- "index": 3,
45
- "tag": "section",
46
- "id": "",
47
- "class": "section-endless-entertainment-gallery",
48
- "top": 3984,
49
- "height": 957,
50
- "animations": [
51
- {
52
- "target": "a.media-gallery-dotnav-link dotnav-link",
53
- "timeline": "document",
54
- "range": null,
55
- "duration": 4160
56
- }
57
- ]
58
- },
59
- {
60
- "index": 4,
61
- "tag": "footer",
62
- "id": "ac-globalfooter",
63
- "class": "js",
64
- "top": 4941,
65
- "height": 1111,
66
- "animations": []
67
- },
68
- {
69
- "index": 5,
70
- "tag": "section",
71
- "id": "",
72
- "class": "ac-gf-sosumi",
73
- "top": 4941,
74
- "height": 525,
75
- "animations": []
76
- },
77
- {
78
- "index": 6,
79
- "tag": "section",
80
- "id": "",
81
- "class": "ac-gf-footer",
82
- "top": 5926,
83
- "height": 126,
84
- "animations": []
85
- }
86
- ],
87
- "screenshots": {
88
- "390": "screen-390.png",
89
- "1440": "screen-1440.png"
90
- }
91
- }
Binary file