diff --git a/site/catalog.html b/site/catalog.html
index 7eb65f5..c9a12f2 100644
--- a/site/catalog.html
+++ b/site/catalog.html
@@ -6,15 +6,16 @@
Lesson Catalog - Course: Computer Science
+
-
-
+
+
-
+
diff --git a/site/glossary.html b/site/glossary.html
index 36c208f..8cff7ac 100644
--- a/site/glossary.html
+++ b/site/glossary.html
@@ -6,15 +6,16 @@
CS Glossary - Course: Computer Science
+
-
-
+
+
-
+
diff --git a/site/index.html b/site/index.html
index 7a2b301..0de16eb 100644
--- a/site/index.html
+++ b/site/index.html
@@ -6,15 +6,16 @@
Course: Computer Science
+
-
-
+
+
-
+
diff --git a/site/lesson.html b/site/lesson.html
index dd898e6..4c1e05d 100644
--- a/site/lesson.html
+++ b/site/lesson.html
@@ -8,13 +8,13 @@
-
+
-
+
diff --git a/site/og-image-1200x630.png b/site/og-image-1200x630.png
new file mode 100644
index 0000000..08ee8b4
Binary files /dev/null and b/site/og-image-1200x630.png differ
diff --git a/site/og-image.svg b/site/og-image.svg
index 18edfa6..0a8ce76 100644
--- a/site/og-image.svg
+++ b/site/og-image.svg
@@ -48,7 +48,7 @@
- Computer Science
+ Computer Science
@@ -58,7 +58,7 @@
- Build production-grade AI systems from first principles.
+ Build computer science from first principles.
@@ -71,6 +71,6 @@
- 20 PHASES · 416 LESSONS · OPEN SOURCE
+ 20 PHASES · 421 LESSONS · OPEN SOURCE
diff --git a/site/prereqs.html b/site/prereqs.html
index f972378..ab4cf0a 100644
--- a/site/prereqs.html
+++ b/site/prereqs.html
@@ -6,15 +6,16 @@
Roadmap - Course: Computer Science
+
-
-
+
+
-
+
diff --git a/tests/social-preview.test.cjs b/tests/social-preview.test.cjs
new file mode 100644
index 0000000..c1ab724
--- /dev/null
+++ b/tests/social-preview.test.cjs
@@ -0,0 +1,38 @@
+const test = require('node:test');
+const assert = require('node:assert/strict');
+const fs = require('node:fs');
+const path = require('node:path');
+
+const SITE = path.join(__dirname, '..', 'site');
+const ORIGIN = 'https://course-computer-science.riteshrana.engineer';
+const IMAGE = `${ORIGIN}/og-image-1200x630.png`;
+
+for (const page of ['index.html', 'catalog.html', 'glossary.html', 'prereqs.html', 'lesson.html']) {
+ test(`${page} shares the raster preview image`, () => {
+ const html = fs.readFileSync(path.join(SITE, page), 'utf8');
+ assert.match(html, //);
+ assert.ok(html.includes(``));
+ assert.ok(html.includes(``));
+ });
+}
+
+for (const [page, pathname] of [
+ ['index.html', '/'],
+ ['catalog.html', '/catalog.html'],
+ ['glossary.html', '/glossary.html'],
+ ['prereqs.html', '/prereqs.html'],
+]) {
+ test(`${page} uses its absolute canonical URL`, () => {
+ const html = fs.readFileSync(path.join(SITE, page), 'utf8');
+ const expected = `${ORIGIN}${pathname}`;
+ assert.ok(html.includes(``));
+ assert.ok(html.includes(``));
+ });
+}
+
+test('social preview is a 1200 by 630 PNG', () => {
+ const png = fs.readFileSync(path.join(SITE, 'og-image-1200x630.png'));
+ assert.equal(png.subarray(0, 8).toString('hex'), '89504e470d0a1a0a');
+ assert.equal(png.readUInt32BE(16), 1200);
+ assert.equal(png.readUInt32BE(20), 630);
+});