feat: favicon + Open Graph / Twitter share tags with image

- Brand ◢ chisel-wedge favicon (SVG + 32px PNG + 180px apple-touch-icon)
- 1200x630 OG share card (Say it. Shape it. + isometric wireframe), rendered
  from HTML via headless Brave; source in step-service/.render/
- og:/twitter: meta with image, theme-color
- vite publicDir=static so assets ship in the build

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
maverick 2026-07-25 19:08:23 +10:00
parent b2a52525d6
commit 1a687ae188
9 changed files with 120 additions and 2 deletions

1
.gitignore vendored
View file

@ -4,3 +4,4 @@ public/
.dev.vars
*.log
.DS_Store
step-service/.render/*.png

View file

@ -4,7 +4,31 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Chisel — AI CAD</title>
<meta name="description" content="Say it. Shape it. Message what you want built and watch it appear in 3D — exportable to real CAD." />
<meta name="description" content="Say it. Shape it. Message what you want built and watch it appear in 3D — exportable to real CAD (STEP)." />
<meta name="theme-color" content="#0B0B09" />
<!-- Favicons -->
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<!-- Open Graph -->
<meta property="og:type" content="website" />
<meta property="og:site_name" content="Chisel" />
<meta property="og:title" content="Chisel — AI CAD" />
<meta property="og:description" content="Say it. Shape it. Describe what you want built and watch it appear in 3D — export real, editable STEP files." />
<meta property="og:url" content="https://chisel.theradicalparty.com/" />
<meta property="og:image" content="https://chisel.theradicalparty.com/og-image.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="Chisel — Say it. Shape it. AI CAD." />
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Chisel — AI CAD" />
<meta name="twitter:description" content="Say it. Shape it. Describe what you want built and watch it appear in 3D — export real, editable STEP files." />
<meta name="twitter:image" content="https://chisel.theradicalparty.com/og-image.png" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 610 B

View file

@ -0,0 +1,7 @@
<svg width="64" height="64" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
<rect width="64" height="64" rx="14" fill="#0B0B09"/>
<!-- ◢ chisel wedge, matching the wordmark -->
<path d="M13 51 L51 51 L51 13 Z" fill="#FF2D55"/>
<!-- bright cutting edge along the blade -->
<path d="M13 51 L51 13" stroke="#FF9FB0" stroke-width="3" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

View file

@ -0,0 +1,15 @@
<!doctype html>
<html>
<head><meta charset="utf-8" /><style>
* { margin: 0; padding: 0; }
html, body { width: 512px; height: 512px; overflow: hidden; background: #0B0B09; }
svg { display: block; }
</style></head>
<body>
<svg width="512" height="512" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
<rect width="64" height="64" rx="14" fill="#0B0B09"/>
<path d="M13 51 L51 51 L51 13 Z" fill="#FF2D55"/>
<path d="M13 51 L51 13" stroke="#FF9FB0" stroke-width="3" stroke-linecap="round"/>
</svg>
</body>
</html>

View file

@ -0,0 +1,70 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@600;700;800&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet" />
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { width: 1200px; height: 630px; overflow: hidden; }
body {
background: #0B0B09;
font-family: "IBM Plex Mono", monospace;
color: #ece9e2;
position: relative;
}
/* blueprint grid */
.grid {
position: absolute; inset: 0;
background-image:
linear-gradient(#1b1b17 1px, transparent 1px),
linear-gradient(90deg, #1b1b17 1px, transparent 1px);
background-size: 40px 40px;
mask-image: radial-gradient(circle at 30% 45%, #000 30%, transparent 78%);
-webkit-mask-image: radial-gradient(circle at 30% 45%, #000 30%, transparent 78%);
}
.glow { position: absolute; width: 700px; height: 700px; right: -160px; top: -120px;
background: radial-gradient(circle, rgba(255,45,85,.16), transparent 62%); }
.wrap { position: relative; height: 100%; display: flex; align-items: center; padding: 0 80px; }
.left { flex: 1; }
.mark { display: flex; align-items: center; gap: 18px; margin-bottom: 30px; }
.wedge { width: 54px; height: 54px; }
.logo { font-family: "Syne", sans-serif; font-weight: 800; font-size: 60px; letter-spacing: 2px; color: #FF2D55; }
h1 { font-family: "Syne", sans-serif; font-weight: 700; font-size: 66px; line-height: 1.05; margin-bottom: 24px; }
h1 .red { color: #FF2D55; }
p { font-size: 24px; line-height: 1.5; color: #b8b4a9; max-width: 620px; }
.url { position: absolute; bottom: 46px; left: 80px; font-size: 22px; color: #8a877e; letter-spacing: 1px; }
.badges { position: absolute; bottom: 44px; right: 80px; display: flex; gap: 10px; }
.badge { border: 1px solid #2c2c26; border-radius: 20px; padding: 8px 16px; font-size: 18px; color: #b8b4a9; }
/* isometric wireframe cube on the right */
.art { width: 360px; height: 360px; margin-left: 40px; }
</style>
</head>
<body>
<div class="grid"></div>
<div class="glow"></div>
<div class="wrap">
<div class="left">
<div class="mark">
<svg class="wedge" viewBox="0 0 64 64"><rect width="64" height="64" rx="14" fill="#141210"/><path d="M13 51 L51 51 L51 13 Z" fill="#FF2D55"/><path d="M13 51 L51 13" stroke="#FF9FB0" stroke-width="3" stroke-linecap="round"/></svg>
<span class="logo">CHISEL</span>
</div>
<h1>Say it.<br /><span class="red">Shape it.</span></h1>
<p>AI CAD — describe what you want built and watch it appear in 3D. Export real, editable STEP files.</p>
</div>
<svg class="art" viewBox="0 0 200 200" fill="none" stroke="#FF2D55" stroke-width="1.6" stroke-linejoin="round">
<!-- isometric cube -->
<path d="M100 20 L170 60 L170 140 L100 180 L30 140 L30 60 Z" opacity="0.35"/>
<path d="M100 20 L100 100 M100 100 L170 60 M100 100 L30 60" opacity="0.5"/>
<path d="M100 100 L100 180" opacity="0.5"/>
<path d="M30 60 L100 100 L170 60" opacity="0.9"/>
<path d="M30 140 L100 180 L170 140" opacity="0.5"/>
<circle cx="100" cy="100" r="4" fill="#FF2D55" stroke="none"/>
</svg>
</div>
<div class="url">chisel.theradicalparty.com</div>
<div class="badges">
<span class="badge">3D preview</span>
<span class="badge">STEP export</span>
</div>
</body>
</html>

View file

@ -6,7 +6,8 @@ import react from "@vitejs/plugin-react";
// the SPA. In dev, `vite` proxies /api to `wrangler dev` on :8787.
export default defineConfig({
root: "src/client",
publicDir: false,
// Static assets (favicon, share image) copied verbatim into the build output.
publicDir: "static",
build: {
outDir: "../../public",
emptyOutDir: true,