Updates companany list to reflect new companies that signed the open weight american leadership paper like spacexai and sakana for example

#1
README.md CHANGED
@@ -10,7 +10,7 @@ pinned: false
10
 
11
  # Open Weights Breakout
12
 
13
- A stripped-down Breakout game built from all 50 logos on Microsoft’s
14
  [Open Weights and American AI Leadership](https://www.microsoft.com/en-us/corporate-responsibility/topics/open-weight/)
15
  signatory wall.
16
 
 
10
 
11
  # Open Weights Breakout
12
 
13
+ A stripped-down Breakout game built from all 77 logos on Microsoft’s
14
  [Open Weights and American AI Leadership](https://www.microsoft.com/en-us/corporate-responsibility/topics/open-weight/)
15
  signatory wall.
16
 
app/LogoBreakout.tsx CHANGED
@@ -4,41 +4,58 @@ import { useCallback, useEffect, useRef, useState } from "react";
4
 
5
  const WIDTH = 1120;
6
  const HEIGHT = 700;
7
- const BRICK_COLUMNS = 8;
8
  const ACCENTS = ["#2d9cdb", "#7fba00", "#ffb900", "#f25022", "#67e8f9"];
9
 
10
  const LOGOS = [
 
11
  ["AI21", "ai21"],
12
  ["AMD", "amd"],
13
  ["American Innovators Network", "american-innovators-network"],
14
  ["AMP", "amp"],
15
  ["Andreessen Horowitz", "andreessen-horowitz"],
 
16
  ["Arcee AI", "arcee-ai"],
17
  ["Arena", "arena"],
 
18
  ["Baseten", "baseten"],
19
  ["Black Forest Labs", "black-forest-labs"],
20
  ["Block", "block"],
 
21
  ["Box", "box"],
 
22
  ["Cisco", "cisco"],
23
  ["Cloudflare", "cloudflare"],
24
  ["Cohere", "cohere"],
 
25
  ["CrowdStrike", "crowdstrike"],
26
  ["Dell Technologies", "dell-technologies"],
27
  ["DoorDash", "doordash"],
 
28
  ["Emergence Capital", "emergence-capital"],
 
 
29
  ["Fireworks AI", "fireworks-ai"],
30
  ["Genspark", "genspark"],
31
  ["GitHub", "github"],
 
32
  ["Google", "google"],
 
33
  ["Hugging Face", "hugging-face"],
 
34
  ["IBM", "ibm"],
35
  ["Inferact", "inferact"],
 
36
  ["Interconnects AI", "interconnects-ai"],
 
37
  ["The Linux Foundation", "linux-foundation"],
 
 
38
  ["Mariana Minerals", "mariana-minerals"],
39
  ["Meta", "meta"],
40
  ["Microsoft", "microsoft"],
41
  ["Mistral", "mistral"],
 
42
  ["Morph", "morph"],
43
  ["Mozilla", "mozilla"],
44
  ["Nebius", "nebius"],
@@ -51,15 +68,27 @@ const LOGOS = [
51
  ["Palo Alto Networks", "palo-alto-networks"],
52
  ["Periodic Labs", "periodic-labs"],
53
  ["Perplexity", "perplexity"],
 
54
  ["Prime Intellect", "prime-intellect"],
 
 
55
  ["Reflection", "reflection"],
 
56
  ["Replit", "replit"],
 
 
57
  ["ServiceNow", "servicenow"],
 
58
  ["Telnyx", "telnyx"],
59
  ["Trajectory", "trajectory"],
 
 
 
60
  ["Y Combinator", "y-combinator"],
61
  ] as const;
62
 
 
 
63
  type Status = "loading" | "ready" | "running" | "paused" | "won" | "lost";
64
 
65
  type Brick = {
@@ -104,12 +133,14 @@ const loadImage = (src: string) =>
104
  image.src = src;
105
  });
106
 
 
 
107
  const createBricks = (images: HTMLImageElement[]): Brick[] => {
108
- const marginX = 28;
109
- const gapX = 10;
110
- const gapY = 7;
111
  const width = (WIDTH - marginX * 2 - gapX * (BRICK_COLUMNS - 1)) / BRICK_COLUMNS;
112
- const height = 64;
113
  const startY = 32;
114
 
115
  return LOGOS.map(([name], index) => {
@@ -359,7 +390,7 @@ export function LogoBreakout() {
359
  burst(game, brick);
360
  tone(610 + (game.destroyed % 7) * 48);
361
 
362
- if (game.destroyed === LOGOS.length) {
363
  game.status = "won";
364
  tone(880, 0.32);
365
  }
@@ -475,16 +506,26 @@ export function LogoBreakout() {
475
  context.save();
476
  const cropX = brick.image.naturalWidth * 0.07;
477
  const cropY = brick.image.naturalHeight * 0.07;
 
 
 
 
 
 
 
 
 
 
478
  context.drawImage(
479
  brick.image,
480
  cropX,
481
  cropY,
482
- brick.image.naturalWidth - cropX * 2,
483
- brick.image.naturalHeight - cropY * 2,
484
- brick.x,
485
- brick.y,
486
- brick.width,
487
- brick.height,
488
  );
489
  context.restore();
490
  }
@@ -585,7 +626,7 @@ export function LogoBreakout() {
585
  loading: {
586
  kicker: "Initializing field",
587
  title: "Loading logos",
588
- copy: "Preparing all 50 signatory nodes.",
589
  action: "Please wait",
590
  },
591
  ready: {
@@ -603,13 +644,13 @@ export function LogoBreakout() {
603
  won: {
604
  kicker: "Mission complete",
605
  title: "Field cleared",
606
- copy: "All 50 signatory logos are down. The weights are open.",
607
  action: "Play again",
608
  },
609
  lost: {
610
  kicker: "Signal lost",
611
  title: "Try another run",
612
- copy: `${destroyed} of 50 logos cleared. Reconnect and finish the field.`,
613
  action: "Restart mission",
614
  },
615
  running: null,
@@ -630,7 +671,9 @@ export function LogoBreakout() {
630
  </div>
631
  <div className="hud-item">
632
  <span>Cleared</span>
633
- <strong>{destroyed}/50</strong>
 
 
634
  </div>
635
  </div>
636
  <div className="console-actions">
@@ -671,7 +714,7 @@ export function LogoBreakout() {
671
  ref={canvasRef}
672
  width={WIDTH}
673
  height={HEIGHT}
674
- aria-label="Breakout playfield containing 50 company logo bricks"
675
  />
676
  {overlay && (
677
  <div className="game-overlay">
 
4
 
5
  const WIDTH = 1120;
6
  const HEIGHT = 700;
7
+ const BRICK_COLUMNS = 11;
8
  const ACCENTS = ["#2d9cdb", "#7fba00", "#ffb900", "#f25022", "#67e8f9"];
9
 
10
  const LOGOS = [
11
+ ["Agno", "agno"],
12
  ["AI21", "ai21"],
13
  ["AMD", "amd"],
14
  ["American Innovators Network", "american-innovators-network"],
15
  ["AMP", "amp"],
16
  ["Andreessen Horowitz", "andreessen-horowitz"],
17
+ ["Applied Compute", "applied-compute"],
18
  ["Arcee AI", "arcee-ai"],
19
  ["Arena", "arena"],
20
+ ["Atreides Management", "atreides-management"],
21
  ["Baseten", "baseten"],
22
  ["Black Forest Labs", "black-forest-labs"],
23
  ["Block", "block"],
24
+ ["Bolt", "bolt"],
25
  ["Box", "box"],
26
+ ["Camber", "camber"],
27
  ["Cisco", "cisco"],
28
  ["Cloudflare", "cloudflare"],
29
  ["Cohere", "cohere"],
30
+ ["Core Automation", "core-automation"],
31
  ["CrowdStrike", "crowdstrike"],
32
  ["Dell Technologies", "dell-technologies"],
33
  ["DoorDash", "doordash"],
34
+ ["EdgeRunner", "edgerunner"],
35
  ["Emergence Capital", "emergence-capital"],
36
+ ["Exia Labs", "exia-labs"],
37
+ ["Fastino Labs", "fastino-labs"],
38
  ["Fireworks AI", "fireworks-ai"],
39
  ["Genspark", "genspark"],
40
  ["GitHub", "github"],
41
+ ["Glean", "glean"],
42
  ["Google", "google"],
43
+ ["GPU MODE", "gpu-mode"],
44
  ["Hugging Face", "hugging-face"],
45
+ ["humans&", "humans-and"],
46
  ["IBM", "ibm"],
47
  ["Inferact", "inferact"],
48
+ ["Intangible", "intangible"],
49
  ["Interconnects AI", "interconnects-ai"],
50
+ ["LangChain", "langchain"],
51
  ["The Linux Foundation", "linux-foundation"],
52
+ ["LM Studio", "lm-studio"],
53
+ ["LMSYS", "lmsys"],
54
  ["Mariana Minerals", "mariana-minerals"],
55
  ["Meta", "meta"],
56
  ["Microsoft", "microsoft"],
57
  ["Mistral", "mistral"],
58
+ ["Modal", "modal"],
59
  ["Morph", "morph"],
60
  ["Mozilla", "mozilla"],
61
  ["Nebius", "nebius"],
 
68
  ["Palo Alto Networks", "palo-alto-networks"],
69
  ["Periodic Labs", "periodic-labs"],
70
  ["Perplexity", "perplexity"],
71
+ ["Plastic Labs", "plastic-labs"],
72
  ["Prime Intellect", "prime-intellect"],
73
+ ["PrismML", "prismml"],
74
+ ["RadixArk", "radixark"],
75
  ["Reflection", "reflection"],
76
+ ["Rehearsals", "rehearsals"],
77
  ["Replit", "replit"],
78
+ ["Sakana AI", "sakana-ai"],
79
+ ["Scale", "scale"],
80
  ["ServiceNow", "servicenow"],
81
+ ["SpaceX", "spacex"],
82
  ["Telnyx", "telnyx"],
83
  ["Trajectory", "trajectory"],
84
+ ["Unsloth", "unsloth"],
85
+ ["Unusual Ventures", "unusual-ventures"],
86
+ ["Vercel", "vercel"],
87
  ["Y Combinator", "y-combinator"],
88
  ] as const;
89
 
90
+ const LOGO_COUNT = LOGOS.length;
91
+
92
  type Status = "loading" | "ready" | "running" | "paused" | "won" | "lost";
93
 
94
  type Brick = {
 
133
  image.src = src;
134
  });
135
 
136
+ // 77 signatories fill an exact 11 x 7 grid, so the wall has no ragged last row
137
+ // and still clears the paddle with room for the ball to work.
138
  const createBricks = (images: HTMLImageElement[]): Brick[] => {
139
+ const marginX = 26;
140
+ const gapX = 9;
141
+ const gapY = 12;
142
  const width = (WIDTH - marginX * 2 - gapX * (BRICK_COLUMNS - 1)) / BRICK_COLUMNS;
143
+ const height = 54;
144
  const startY = 32;
145
 
146
  return LOGOS.map(([name], index) => {
 
390
  burst(game, brick);
391
  tone(610 + (game.destroyed % 7) * 48);
392
 
393
+ if (game.destroyed === LOGO_COUNT) {
394
  game.status = "won";
395
  tone(880, 0.32);
396
  }
 
506
  context.save();
507
  const cropX = brick.image.naturalWidth * 0.07;
508
  const cropY = brick.image.naturalHeight * 0.07;
509
+ const sourceWidth = brick.image.naturalWidth - cropX * 2;
510
+ const sourceHeight = brick.image.naturalHeight - cropY * 2;
511
+ // Contain the mark in its brick rather than stretching it, so a denser
512
+ // grid keeps every wordmark at its own proportions.
513
+ const scale = Math.min(
514
+ brick.width / sourceWidth,
515
+ brick.height / sourceHeight,
516
+ );
517
+ const drawWidth = sourceWidth * scale;
518
+ const drawHeight = sourceHeight * scale;
519
  context.drawImage(
520
  brick.image,
521
  cropX,
522
  cropY,
523
+ sourceWidth,
524
+ sourceHeight,
525
+ brick.x + (brick.width - drawWidth) / 2,
526
+ brick.y + (brick.height - drawHeight) / 2,
527
+ drawWidth,
528
+ drawHeight,
529
  );
530
  context.restore();
531
  }
 
626
  loading: {
627
  kicker: "Initializing field",
628
  title: "Loading logos",
629
+ copy: `Preparing all ${LOGO_COUNT} signatory nodes.`,
630
  action: "Please wait",
631
  },
632
  ready: {
 
644
  won: {
645
  kicker: "Mission complete",
646
  title: "Field cleared",
647
+ copy: `All ${LOGO_COUNT} signatory logos are down. The weights are open.`,
648
  action: "Play again",
649
  },
650
  lost: {
651
  kicker: "Signal lost",
652
  title: "Try another run",
653
+ copy: `${destroyed} of ${LOGO_COUNT} logos cleared. Reconnect and finish the field.`,
654
  action: "Restart mission",
655
  },
656
  running: null,
 
671
  </div>
672
  <div className="hud-item">
673
  <span>Cleared</span>
674
+ <strong>
675
+ {destroyed}/{LOGO_COUNT}
676
+ </strong>
677
  </div>
678
  </div>
679
  <div className="console-actions">
 
714
  ref={canvasRef}
715
  width={WIDTH}
716
  height={HEIGHT}
717
+ aria-label={`Breakout playfield containing ${LOGO_COUNT} company logo bricks`}
718
  />
719
  {overlay && (
720
  <div className="game-overlay">
app/layout.tsx CHANGED
@@ -4,7 +4,7 @@ import "./globals.css";
4
  export const metadata: Metadata = {
5
  title: "Open Weights Breakout",
6
  description:
7
- "A 50-logo Breakout game with Anthropic at the controls.",
8
  icons: {
9
  icon: "/anthropic-wordmark.png",
10
  shortcut: "/anthropic-wordmark.png",
 
4
  export const metadata: Metadata = {
5
  title: "Open Weights Breakout",
6
  description:
7
+ "A 77-logo Breakout game with Anthropic at the controls.",
8
  icons: {
9
  icon: "/anthropic-wordmark.png",
10
  shortcut: "/anthropic-wordmark.png",
public/logos/agno.png ADDED
public/logos/applied-compute.png ADDED
public/logos/atreides-management.png ADDED
public/logos/bolt.png ADDED
public/logos/camber.png ADDED
public/logos/core-automation.png ADDED
public/logos/edgerunner.png ADDED
public/logos/exia-labs.png ADDED
public/logos/fastino-labs.png ADDED
public/logos/glean.png ADDED
public/logos/gpu-mode.png ADDED
public/logos/humans-and.png ADDED
public/logos/intangible.png ADDED
public/logos/langchain.png ADDED
public/logos/lm-studio.png ADDED
public/logos/lmsys.png ADDED
public/logos/modal.png ADDED
public/logos/plastic-labs.png ADDED
public/logos/prismml.png ADDED
public/logos/radixark.png ADDED
public/logos/rehearsals.png ADDED
public/logos/sakana-ai.png ADDED
public/logos/scale.png ADDED
public/logos/spacex.png ADDED
public/logos/unsloth.png ADDED
public/logos/unusual-ventures.png ADDED
public/logos/vercel.png ADDED
scripts/download-logos.mjs CHANGED
@@ -1,40 +1,58 @@
1
- import { mkdir, writeFile } from "node:fs/promises";
2
 
3
  const PAGE_URL =
4
  "https://www.microsoft.com/en-us/corporate-responsibility/topics/open-weight/";
5
 
 
6
  const logos = [
 
7
  ["AI21", "AI21", "ai21"],
8
  ["AMD", "AMD", "amd"],
9
  ["American Innovators Network", "American Innovators Network", "american-innovators-network"],
10
  ["AMP", "AMP", "amp"],
11
  ["Andreessen Horowitz", "Andreessen Horowitz", "andreessen-horowitz"],
 
12
  ["Arcee AI", "Arcee", "arcee-ai"],
13
  ["Arena", "Arena", "arena"],
 
14
  ["Baseten", "Baseten", "baseten"],
15
  ["Black Forest Labs", "Black Forest Labs", "black-forest-labs"],
16
  ["Block", "Block", "block"],
 
17
  ["Box", "Box", "box"],
 
18
  ["Cisco", "Cisco", "cisco"],
19
  ["Cloudflare", "Cloudflare", "cloudflare"],
20
  ["Cohere", "Cohere", "cohere"],
 
21
  ["CrowdStrike", "Crowdstrike", "crowdstrike"],
22
  ["Dell Technologies", "Dell Technologies", "dell-technologies"],
23
  ["DoorDash", "DoorDash", "doordash"],
 
24
  ["Emergence Capital", "Emergence", "emergence-capital"],
 
 
25
  ["Fireworks AI", "Fireworks AI", "fireworks-ai"],
26
  ["Genspark", "Genspark", "genspark"],
27
  ["GitHub", "GitHub", "github"],
 
28
  ["Google", "Google", "google"],
 
29
  ["Hugging Face", "Hugging Face", "hugging-face"],
 
30
  ["IBM", "IBM", "ibm"],
31
  ["Inferact", "Inferact", "inferact"],
 
32
  ["Interconnects AI", "Interconnects AI", "interconnects-ai"],
 
33
  ["The Linux Foundation", "Linux Foundation", "linux-foundation"],
 
 
34
  ["Mariana Minerals", "Mariana Minerals", "mariana-minerals"],
35
  ["Meta", "Meta", "meta"],
36
  ["Microsoft", "Microsoft", "microsoft"],
37
  ["Mistral", "Mistral", "mistral"],
 
38
  ["Morph", "Morph", "morph"],
39
  ["Mozilla", "Mozilla", "mozilla"],
40
  ["Nebius", "Nebius", "nebius"],
@@ -47,12 +65,22 @@ const logos = [
47
  ["Palo Alto Networks", "Palo Alto Networks", "palo-alto-networks"],
48
  ["Periodic Labs", "Periodic Labs", "periodic-labs"],
49
  ["Perplexity", "Perplexity", "perplexity"],
 
50
  ["Prime Intellect", "Prime Intellect", "prime-intellect"],
 
 
51
  ["Reflection", "Reflection", "reflection"],
 
52
  ["Replit", "Replit", "replit"],
 
 
53
  ["ServiceNow", "ServiceNow", "servicenow"],
 
54
  ["Telnyx", "Telnyx", "telnyx"],
55
  ["Trajectory", "Trajectory", "trajectory"],
 
 
 
56
  ["Y Combinator", "Y-Combinator", "y-combinator"],
57
  ];
58
 
@@ -79,6 +107,7 @@ for (const tag of imageTags) {
79
 
80
  await mkdir(new URL("../public/logos/", import.meta.url), { recursive: true });
81
 
 
82
  for (const [name, sourceAlt, slug] of logos) {
83
  const url = byAlt.get(sourceAlt);
84
  if (!url) throw new Error(`Missing source image for ${name}`);
@@ -89,8 +118,16 @@ for (const [name, sourceAlt, slug] of logos) {
89
  }
90
 
91
  const bytes = new Uint8Array(await response.arrayBuffer());
92
- await writeFile(new URL(`../public/logos/${slug}.png`, import.meta.url), bytes);
 
 
 
 
 
 
 
 
93
  console.log(`${name}: ${bytes.length} bytes`);
94
  }
95
 
96
- console.log(`Downloaded ${logos.length} logo bricks.`);
 
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
 
3
  const PAGE_URL =
4
  "https://www.microsoft.com/en-us/corporate-responsibility/topics/open-weight/";
5
 
6
+ // [display name, alt text on the signatory wall, local slug]
7
  const logos = [
8
+ ["Agno", "Agno", "agno"],
9
  ["AI21", "AI21", "ai21"],
10
  ["AMD", "AMD", "amd"],
11
  ["American Innovators Network", "American Innovators Network", "american-innovators-network"],
12
  ["AMP", "AMP", "amp"],
13
  ["Andreessen Horowitz", "Andreessen Horowitz", "andreessen-horowitz"],
14
+ ["Applied Compute", "Applied Compute", "applied-compute"],
15
  ["Arcee AI", "Arcee", "arcee-ai"],
16
  ["Arena", "Arena", "arena"],
17
+ ["Atreides Management", "Artriedes Management", "atreides-management"],
18
  ["Baseten", "Baseten", "baseten"],
19
  ["Black Forest Labs", "Black Forest Labs", "black-forest-labs"],
20
  ["Block", "Block", "block"],
21
+ ["Bolt", "Bolt", "bolt"],
22
  ["Box", "Box", "box"],
23
+ ["Camber", "Camber", "camber"],
24
  ["Cisco", "Cisco", "cisco"],
25
  ["Cloudflare", "Cloudflare", "cloudflare"],
26
  ["Cohere", "Cohere", "cohere"],
27
+ ["Core Automation", "Core Automation", "core-automation"],
28
  ["CrowdStrike", "Crowdstrike", "crowdstrike"],
29
  ["Dell Technologies", "Dell Technologies", "dell-technologies"],
30
  ["DoorDash", "DoorDash", "doordash"],
31
+ ["EdgeRunner", "EdgeRunner", "edgerunner"],
32
  ["Emergence Capital", "Emergence", "emergence-capital"],
33
+ ["Exia Labs", "Exia Labs", "exia-labs"],
34
+ ["Fastino Labs", "Fastino", "fastino-labs"],
35
  ["Fireworks AI", "Fireworks AI", "fireworks-ai"],
36
  ["Genspark", "Genspark", "genspark"],
37
  ["GitHub", "GitHub", "github"],
38
+ ["Glean", "Glean", "glean"],
39
  ["Google", "Google", "google"],
40
+ ["GPU MODE", "GPU MODE", "gpu-mode"],
41
  ["Hugging Face", "Hugging Face", "hugging-face"],
42
+ ["humans&", "humans and", "humans-and"],
43
  ["IBM", "IBM", "ibm"],
44
  ["Inferact", "Inferact", "inferact"],
45
+ ["Intangible", "Intangible", "intangible"],
46
  ["Interconnects AI", "Interconnects AI", "interconnects-ai"],
47
+ ["LangChain", "LangChain", "langchain"],
48
  ["The Linux Foundation", "Linux Foundation", "linux-foundation"],
49
+ ["LM Studio", "LM Studio", "lm-studio"],
50
+ ["LMSYS", "LMSYS", "lmsys"],
51
  ["Mariana Minerals", "Mariana Minerals", "mariana-minerals"],
52
  ["Meta", "Meta", "meta"],
53
  ["Microsoft", "Microsoft", "microsoft"],
54
  ["Mistral", "Mistral", "mistral"],
55
+ ["Modal", "Modal", "modal"],
56
  ["Morph", "Morph", "morph"],
57
  ["Mozilla", "Mozilla", "mozilla"],
58
  ["Nebius", "Nebius", "nebius"],
 
65
  ["Palo Alto Networks", "Palo Alto Networks", "palo-alto-networks"],
66
  ["Periodic Labs", "Periodic Labs", "periodic-labs"],
67
  ["Perplexity", "Perplexity", "perplexity"],
68
+ ["Plastic Labs", "Plastic Labs", "plastic-labs"],
69
  ["Prime Intellect", "Prime Intellect", "prime-intellect"],
70
+ ["PrismML", "PrismML", "prismml"],
71
+ ["RadixArk", "RadixArk", "radixark"],
72
  ["Reflection", "Reflection", "reflection"],
73
+ ["Rehearsals", "Rehearsals", "rehearsals"],
74
  ["Replit", "Replit", "replit"],
75
+ ["Sakana AI", "Sakana AI", "sakana-ai"],
76
+ ["Scale", "Scale", "scale"],
77
  ["ServiceNow", "ServiceNow", "servicenow"],
78
+ ["SpaceX", "SpaceX", "spacex"],
79
  ["Telnyx", "Telnyx", "telnyx"],
80
  ["Trajectory", "Trajectory", "trajectory"],
81
+ ["Unsloth", "Unsloth", "unsloth"],
82
+ ["Unusual Ventures", "Unusual", "unusual-ventures"],
83
+ ["Vercel", "Vercel", "vercel"],
84
  ["Y Combinator", "Y-Combinator", "y-combinator"],
85
  ];
86
 
 
107
 
108
  await mkdir(new URL("../public/logos/", import.meta.url), { recursive: true });
109
 
110
+ let written = 0;
111
  for (const [name, sourceAlt, slug] of logos) {
112
  const url = byAlt.get(sourceAlt);
113
  if (!url) throw new Error(`Missing source image for ${name}`);
 
118
  }
119
 
120
  const bytes = new Uint8Array(await response.arrayBuffer());
121
+ const target = new URL(`../public/logos/${slug}.png`, import.meta.url);
122
+ const existing = await readFile(target).catch(() => null);
123
+ if (existing && existing.equals(Buffer.from(bytes))) {
124
+ console.log(`${name}: unchanged`);
125
+ continue;
126
+ }
127
+
128
+ await writeFile(target, bytes);
129
+ written += 1;
130
  console.log(`${name}: ${bytes.length} bytes`);
131
  }
132
 
133
+ console.log(`${logos.length} logo bricks (${written} written).`);