diff --git a/index.html b/index.html
index 7bc3742..f03d6fd 100644
--- a/index.html
+++ b/index.html
@@ -6,10 +6,23 @@
-->
- WebGL Samples
-
-
-
+ WebGL Samples
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/og-image.png b/og-image.png
new file mode 100644
index 0000000..5b91b3b
Binary files /dev/null and b/og-image.png differ
diff --git a/tools/make-og-image.py b/tools/make-og-image.py
new file mode 100644
index 0000000..a3e731b
--- /dev/null
+++ b/tools/make-og-image.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python3
+"""Generate a 1200x630 OG image for WebGL Samples (webglsamples.org).
+
+Pillow-only, reproducible. Draws a dark 3D wireframe-cube card using the
+site's brand palette (#0090c5 blue, #ff4486 pink) on a dark ground.
+"""
+import os
+from PIL import Image, ImageDraw, ImageFont
+
+W, H = 1200, 630
+BG_TOP = (15, 18, 32)
+BG_BOT = (26, 31, 51)
+BLUE = (0, 144, 197)
+PINK = (255, 68, 134)
+WHITE = (245, 247, 250)
+GREY = (150, 158, 180)
+
+FONT_DIR = os.environ.get("FONT_DIR", "/usr/share/fonts/truetype/dejavu")
+
+
+def font(size, bold=False):
+ name = "DejaVuSans-Bold.ttf" if bold else "DejaVuSans.ttf"
+ p = os.path.join(FONT_DIR, name)
+ if not os.path.exists(p):
+ # fallback to Liberation
+ p = os.path.join(FONT_DIR, "LiberationSans-Bold.ttf" if bold else "LiberationSans-Regular.ttf")
+ return ImageFont.truetype(p, size)
+
+
+def lerp(a, b, t):
+ return tuple(int(a[i] + (b[i] - a[i]) * t) for i in range(3))
+
+
+def draw_cube(d, cx, cy, size, color, width=3):
+ """Isometric wireframe cube centered at (cx, cy)."""
+ s = size
+ # 8 vertices of an isometric cube
+ v = [
+ (cx - s, cy - s * 0.5), # 0 front-left-top
+ (cx + s, cy - s * 0.5), # 1 front-right-top
+ (cx + s, cy + s * 0.5), # 2 front-right-bottom
+ (cx - s, cy + s * 0.5), # 3 front-left-bottom
+ (cx, cy - s * 1.5), # 4 back-top
+ (cx, cy - s * 0.5), # 5 back-bottom
+ ]
+ edges = [
+ (0, 1), (1, 2), (2, 3), (3, 0), # front face
+ (0, 4), (1, 4), (2, 5), (3, 5), # to back
+ (4, 5), # back edge
+ ]
+ for a, b in edges:
+ d.line([v[a], v[b]], fill=color, width=width)
+
+
+def main():
+ img = Image.new("RGB", (W, H))
+ d = ImageDraw.Draw(img)
+ # vertical gradient
+ for y in range(H):
+ t = y / H
+ d.line([(0, y), (W, y)], fill=lerp(BG_TOP, BG_BOT, t))
+
+ # subtle grid dots
+ for gx in range(0, W, 40):
+ for gy in range(0, H, 40):
+ d.ellipse([gx - 1, gy - 1, gx + 1, gy + 1], fill=(40, 46, 70))
+
+ # 3D wireframe cubes (WebGL motif)
+ draw_cube(d, 900, 300, 150, BLUE, width=4)
+ draw_cube(d, 1020, 420, 90, PINK, width=3)
+ draw_cube(d, 780, 430, 60, (70, 90, 130), width=2)
+
+ # Title
+ f_title = font(88, bold=True)
+ d.text((70, 120), "WebGL", fill=WHITE, font=f_title)
+ d.text((70, 220), "Samples", fill=BLUE, font=f_title)
+
+ # Tagline
+ f_tag = font(34)
+ d.text((72, 360), "A place to host and work on", fill=GREY, font=f_tag)
+ d.text((72, 404), "WebGL sample applications", fill=GREY, font=f_tag)
+
+ # Domain
+ f_dom = font(30, bold=True)
+ d.text((72, 520), "webglsamples.org", fill=PINK, font=f_dom)
+
+ out = os.environ.get("OUT", "og-image.png")
+ img.save(out)
+ print("wrote", out, img.size)
+
+
+if __name__ == "__main__":
+ main()