feat(site): 🫙 PCBJam landing revisions — branding, accuracy, positioning graphic

Founder review pass on the landing page, plus commit the landing-page
research/spec docs under features/lp.

Branding & assets:
- New PCBJam mark: convert the jam-jar image to favicon.svg (trimmed, rounded
  tile) and use it in the browser tab, header, and footer.
- Footer "Built by": flower mark + "Emergence Engineering" in white Oswald (the
  blog's title font, self-hosted via @fontsource) so it's legible on dark.
- Produce the positioning quadrant graphic (public/graphics) and drop the placeholder.

Copy / accuracy:
- Remove header GitHub link; point "Built by EE" + footer "About" to
  emergence-engineering.com; Built-by CTA -> mailto:contact@emergence-engineering.com.
- Replace the wrong testimonial with Greg Detre's real quote from EE's site.
- Drop blog icons from Multiplayer/Pillars/How-it-works; add "Coming soon" to
  live-cursors & pin-comment; drop the hard-coded Yjs mention.
- Rework monetization to free+local / paid cloud-sync; remove "no metered AI",
  "no per-seat toll", and the Flux price claim; soften the AI section.
- Reframe waitlist copy (incl. confirmation email) to newsletter + early access.

Fixes:
- Offset only #waitlist for the sticky header (scroll-margin-top); section
  anchors keep their original behavior.

Docs:
- Commit features/lp (copy spec, brand guide, competitive research) via force-add
  over the /features/ gitignore.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Viktor Vaczi 2026-06-07 17:14:19 +02:00
commit 735d8a48ee
31 changed files with 8149 additions and 135 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

10
site/package-lock.json generated
View file

@ -9,6 +9,7 @@
"version": "0.0.1",
"dependencies": {
"@astrojs/vercel": "^10.0.8",
"@fontsource/oswald": "^5.2.8",
"astro": "^6.4.4",
"resend": "^6.12.4"
},
@ -638,6 +639,15 @@
"node": ">=18"
}
},
"node_modules/@fontsource/oswald": {
"version": "5.2.8",
"resolved": "https://registry.npmjs.org/@fontsource/oswald/-/oswald-5.2.8.tgz",
"integrity": "sha512-DFoPK1BqsFIQhVjs2xgO/oL9veF9oUJgFojEWIU+nazUrfqsBDtAMI4n9L9CZFX3kQNDLcCyzKx1xoEDvQT4WQ==",
"license": "OFL-1.1",
"funding": {
"url": "https://github.com/sponsors/ayuhito"
}
},
"node_modules/@img/colour": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz",

View file

@ -14,6 +14,7 @@
},
"dependencies": {
"@astrojs/vercel": "^10.0.8",
"@fontsource/oswald": "^5.2.8",
"astro": "^6.4.4",
"resend": "^6.12.4"
},

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 221 B

After

Width:  |  Height:  |  Size: 32 KiB

Before After
Before After

View file

@ -0,0 +1,60 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 820 600" width="820" height="600" role="img" aria-labelledby="pq-title pq-desc" font-family="system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif">
<title id="pq-title">PCB tool positioning map</title>
<desc id="pq-desc">A quadrant chart. The horizontal axis runs from desktop-install on the left to browser-native on the right; the vertical axis from proprietary at the bottom to open at the top. LibrePCB and KiCad sit top-left (open but desktop). KiCanvas sits top-right but is viewer-only. Flux and EasyEDA sit bottom-right (browser but proprietary). Altium 365 and OrCAD X sit bottom-left (desktop and proprietary). PCBJam sits alone in the top-right as the only browser-native, open, real-time-multiplayer tool.</desc>
<!-- panel -->
<rect x="8" y="8" width="804" height="584" rx="16" fill="#11182e" stroke="#233052" stroke-width="1"/>
<!-- top-right "whitespace" tint -->
<rect x="410" y="64" width="338" height="232" fill="#4f7cff" fill-opacity="0.09"/>
<!-- axes -->
<g stroke="#34436b" stroke-width="2" fill="#34436b">
<line x1="80" y1="296" x2="748" y2="296"/>
<line x1="410" y1="64" x2="410" y2="528"/>
<polygon points="748,296 734,289 734,303" stroke="none"/>
<polygon points="80,296 94,289 94,303" stroke="none"/>
<polygon points="410,64 403,78 417,78" stroke="none"/>
<polygon points="410,528 403,514 417,514" stroke="none"/>
</g>
<!-- axis labels -->
<g fill="#9aa6c0" font-size="14" font-weight="600">
<text x="410" y="50" text-anchor="middle">Open &amp; yours</text>
<text x="410" y="554" text-anchor="middle">Proprietary, locked-in</text>
<text x="92" y="316" text-anchor="start">Desktop install</text>
<text x="736" y="316" text-anchor="end">Browser-native</text>
</g>
<!-- competitors -->
<g fill="#8794ad">
<circle cx="210" cy="150" r="5"/>
<circle cx="250" cy="205" r="5"/>
<circle cx="540" cy="200" r="5"/>
<circle cx="540" cy="372" r="5"/>
<circle cx="596" cy="440" r="5"/>
<circle cx="210" cy="388" r="5"/>
<circle cx="250" cy="448" r="5"/>
</g>
<g fill="#b4bfd6" font-size="15">
<text x="224" y="155">LibrePCB</text>
<text x="264" y="210">KiCad</text>
<text x="554" y="205">KiCanvas</text>
<text x="554" y="377">Flux</text>
<text x="610" y="445">EasyEDA</text>
<text x="224" y="393">Altium 365</text>
<text x="264" y="453">OrCAD X</text>
</g>
<text x="554" y="222" font-size="11" fill="#6b7796">viewer only</text>
<!-- PCBJam marker (the only "all three") -->
<circle cx="590" cy="120" r="30" fill="#4f7cff" fill-opacity="0.12"/>
<text x="590" y="130" text-anchor="middle" font-size="30" fill="#32d583"></text>
<text x="614" y="128" text-anchor="start" font-size="19" font-weight="700" fill="#e7ecf5">PCBJam</text>
<rect x="560" y="140" width="170" height="24" rx="12" fill="#32d583" fill-opacity="0.15" stroke="#32d583" stroke-opacity="0.6"/>
<text x="645" y="156" text-anchor="middle" font-size="12" fill="#32d583" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace">real-time multiplayer</text>
<!-- legend -->
<text x="34" y="580" font-size="14" fill="#32d583"></text>
<text x="50" y="580" font-size="12" fill="#9aa6c0">= true real-time multiplayer (PCBJam only)</text>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

@ -1,11 +1,14 @@
---
/**
* EECredit — the "Built by Emergence Engineering" lockup. The EE wordmark keeps
* its own (guest-brand) colors via Icon mode="img".
* - variant="footer": wordmark + studio blurb + contact (footer column 3).
* - variant="inline": compact wordmark + "Built by" label.
* EECredit — the "Built by Emergence Engineering" lockup.
* Uses the EE flower mark (keeps its orange) + the "Emergence Engineering"
* wordmark set in Oswald (the blog's brand/title font) in a light color, so it
* stays visible on the dark footer (the original wordmark SVG's text is near-black).
* - variant="footer": lockup + studio blurb + contact (footer column 3).
* - variant="inline": compact "Built by" lockup.
*/
import Icon from './Icon.astro';
import '@fontsource/oswald/500.css';
interface Props {
variant?: 'footer' | 'inline';
@ -16,19 +19,33 @@ const { variant = 'footer', class: cls = '' } = Astro.props;
{
variant === 'inline' ? (
<a class={`ee-inline ${cls}`} href="/built-by-emergence">
<a
class={`ee-inline ${cls}`}
href="https://emergence-engineering.com"
target="_blank"
rel="noopener"
>
<span class="ee-by">Built by</span>
<Icon name="ee/ee-logo.svg" mode="img" size="1rem" alt="Emergence Engineering" />
<Icon name="ee/ee-mark.svg" mode="img" size="1rem" alt="" />
<span class="ee-wordmark">Emergence Engineering</span>
</a>
) : (
<div class={`ee-footer ${cls}`}>
<Icon name="ee/ee-logo.svg" mode="img" size="1.5rem" alt="Emergence Engineering" />
<span class="ee-lockup">
<Icon name="ee/ee-mark.svg" mode="img" size="1.6rem" alt="" />
<span class="ee-wordmark">Emergence Engineering</span>
</span>
<p class="ee-blurb muted">
PCBJam is a project by Emergence Engineering, a full-stack software studio. Need
something hard built?{' '}
<a href="mailto:contact@emergence-engineering.com">contact@emergence-engineering.com</a>
</p>
<a class="ee-link" href="/built-by-emergence">
<a
class="ee-link"
href="https://emergence-engineering.com"
target="_blank"
rel="noopener"
>
About Emergence Engineering →
</a>
</div>
@ -36,10 +53,17 @@ const { variant = 'footer', class: cls = '' } = Astro.props;
}
<style>
.ee-wordmark {
font-family: 'Oswald', system-ui, sans-serif;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.04em;
color: var(--fg);
}
.ee-inline {
display: inline-flex;
align-items: center;
gap: 0.5rem;
gap: 0.4rem;
color: var(--fg-muted);
}
.ee-inline:hover {
@ -55,6 +79,14 @@ const { variant = 'footer', class: cls = '' } = Astro.props;
gap: 0.6rem;
align-items: flex-start;
}
.ee-lockup {
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
.ee-lockup .ee-wordmark {
font-size: 1.05rem;
}
.ee-blurb {
margin: 0;
font-size: 0.85rem;

View file

@ -11,7 +11,7 @@ const GITHUB_URL = 'https://github.com/emergence-engineering';
<div class="container cols">
<div class="col col-brand">
<a class="brand" href="/">
<img src="/favicon.svg" alt="" width="22" height="22" />
<img src="/favicon.svg" alt="" width="18" height="25" />
<span>PCBJam</span>
</a>
<p class="tagline muted">KiCad, in your browser. Now multiplayer.</p>
@ -85,6 +85,10 @@ const GITHUB_URL = 'https://github.com/emergence-engineering';
font-weight: 700;
color: var(--fg);
}
.brand img {
height: 1.6rem;
width: auto;
}
.tagline {
margin: 0.6rem 0 0.9rem;
}

View file

@ -1,28 +1,27 @@
---
import Icon from './Icon.astro';
// TODO(assets): replace favicon "K" + text wordmark with the real PCBJam logo (§4b.1).
// TODO(links): add "Roadmap" → /roadmap and repoint How-it-works/Open to their own
// pages once the supporting pages ship; for now they anchor to landing sections.
// TODO(config): point at the public PCBJam repo when it exists.
const GITHUB_URL = 'https://github.com/emergence-engineering';
const links = [
{ href: '/#how-it-works', label: 'How it works' },
{ href: '/#open', label: 'Open & yours' },
{ href: '/blog', label: 'Blog' },
{ href: '/#built-by', label: 'Built by Emergence Engineering' },
{
href: 'https://emergence-engineering.com',
label: 'Built by Emergence Engineering',
external: true,
},
];
const path = Astro.url.pathname;
const isActive = (href: string) =>
href.startsWith('/#') ? false : href === '/' ? path === '/' : path.startsWith(href);
const isActive = (href: string, external?: boolean) =>
external || href.startsWith('/#') ? false : href === '/' ? path === '/' : path.startsWith(href);
---
<header class="site-header" transition:persist>
<div class="container bar">
<a class="brand" href="/">
<img src="/favicon.svg" alt="" width="24" height="24" />
<img src="/favicon.svg" alt="" width="20" height="28" />
<span class="brand-name">PCBJam</span>
<span class="brand-chip">built on KiCad</span>
</a>
@ -35,14 +34,16 @@ const isActive = (href: string) =>
<nav class="nav" aria-label="Primary">
{
links.map((l) => (
<a href={l.href} aria-current={isActive(l.href) ? 'page' : undefined}>
<a
href={l.href}
aria-current={isActive(l.href, l.external) ? 'page' : undefined}
rel={l.external ? 'noopener' : undefined}
target={l.external ? '_blank' : undefined}
>
{l.label}
</a>
))
}
<a class="gh" href={GITHUB_URL} rel="noopener" target="_blank">
<Icon name="icons/github.svg" size="1rem" alt="GitHub" /> <span>★</span>
</a>
<a class="btn btn-primary cta-join" href="/#waitlist">Join the waitlist</a>
</nav>
</div>
@ -72,8 +73,8 @@ const isActive = (href: string) =>
gap: 0.5rem;
}
.brand img {
width: 1.5rem;
height: 1.5rem;
height: 1.85rem;
width: auto;
}
.brand-chip {
font-family: var(--font-mono);
@ -99,11 +100,6 @@ const isActive = (href: string) =>
.nav > a[aria-current='page'] {
color: var(--fg);
}
.gh {
display: inline-flex;
align-items: center;
gap: 0.25rem;
}
.cta-join {
padding-block: 0.5rem;
font-size: 0.95rem;
@ -147,8 +143,7 @@ const isActive = (href: string) =>
.nav-toggle:checked ~ .nav {
display: flex;
}
.nav > a,
.gh {
.nav > a {
padding-block: 0.6rem;
border-bottom: 1px solid var(--border);
}

View file

@ -18,7 +18,7 @@ const {
source,
id,
layout = 'row',
microcopy = "Early access rolls out in waves. We'll email you when your seat opens — no spam.",
microcopy = 'Get early-access invites and the occasional product update — no spam, unsubscribe anytime.',
class: cls = '',
} = Astro.props;
@ -60,7 +60,7 @@ const hpId = `wl-hp-${source}`;
<div class="wl-success" hidden data-wl-success>
<strong>You're on the list. 🎉</strong>
<span class="muted">We'll email you when your early-access seat opens — no spam.</span>
<span class="muted">We'll be in touch with product updates and your early-access invite.</span>
</div>
{microcopy && <p class="wl-micro muted">{microcopy}</p>}

View file

@ -79,10 +79,8 @@ export const POST: APIRoute = async ({ request }) => {
text: [
"You're on the list. 🎉",
'',
"We'll email you the moment your early-access seat opens. Early access rolls",
'out in waves — no spam, just a heads-up when your seat is ready.',
'',
'In the meantime: star us on GitHub and follow along.',
"We'll keep you posted with product updates, and send your early-access invite",
'as seats open in waves. No spam — unsubscribe anytime.',
'',
'— The PCBJam team, built by Emergence Engineering',
].join('\n'),

View file

@ -7,11 +7,11 @@ import Icon from '../components/Icon.astro';
<div class="ai">
<Icon name="icons/ai.svg" mode="img" size="2.5rem" alt="" class="ai-icon" />
<div>
<h3 id="ai-h3">AI when you want it. Never a paywall, never a black box.</h3>
<h3 id="ai-h3">AI when you want it — opt-in, never a black box.</h3>
<p class="muted">
Everyone else leads with an “AI hardware engineer.” We lead with <em>you</em> and an open
tool you control. AI assistance is on the roadmap as an <strong>opt-in</strong> helper —
never metered by the token, never the thing standing between you and your own board.
never the thing standing between you and your own board.
</p>
</div>
</div>

View file

@ -44,11 +44,12 @@ const clients = [
</div>
<blockquote class="quote">
“For any new product, theyre my go-to dev house. They work fast and to super high quality.”
<cite>— Ben Whately</cite>
“They are incredibly smart, you can trust them, and theyre great to work with. I cannot
recommend them highly enough.”
<cite>— Greg Detre, Chief Data Scientist &amp; CTO</cite>
</blockquote>
<a class="btn btn-ghost" href="/built-by-emergence">
<a class="btn btn-ghost" href="mailto:contact@emergence-engineering.com">
Need something hard built? → Talk to the team
</a>
</SectionBand>

View file

@ -13,7 +13,7 @@ import WaitlistForm from '../components/WaitlistForm.astro';
<WaitlistForm
source="final"
class="final-form"
microcopy="No spam. One email when your seat is ready. Unsubscribe anytime."
microcopy="Get early-access invites and product updates. No spam, unsubscribe anytime."
/>
<ul class="final-trust">

View file

@ -8,15 +8,15 @@ import Step from '../components/Step.astro';
<h2 id="hiw-h2">From link to layout in three moves.</h2>
</div>
<div class="steps">
<Step n={1} title="Open a board." icon="icons/idea.svg">
<Step n={1} title="Open a board.">
Paste a link, drag in a <code>.kicad_pcb</code>, or pull from GitHub. It opens in seconds —
no install, no account wall to <em>look</em>.
</Step>
<Step n={2} title="Start a jam." icon="icons/prototype.svg">
<Step n={2} title="Start a jam.">
Share the URL. Teammates join with live cursors and presence. Everyone sees the same
board update in real time.
</Step>
<Step n={3} title="Design, route & export — together." icon="icons/product.svg">
<Step n={3} title="Design, route & export — together.">
Schematic capture, PCB layout, DRC/ERC, 3D, BOM, and Gerbers — the full flow, then hand
off to any fab. Your call.
</Step>

View file

@ -2,11 +2,11 @@
import SectionBand from '../components/SectionBand.astro';
const row = [
{ title: 'Free core', body: 'The full editor and real-time collaboration, free to start.' },
{ title: 'Free & local', body: 'The full editor, free. Your files live right in your browser.' },
{ title: 'Open format', body: 'Your .kicad_pcb / .kicad_sch, open forever.' },
{
title: 'Paid for team scale',
body: 'Private org workspaces, SSO, compliance, hosted storage.',
title: 'Paid: cloud & sync',
body: 'Hosted storage, cross-device sync, and shared team workspaces.',
},
];
---
@ -15,16 +15,11 @@ const row = [
<div class="section-head">
<h3 id="money-h3">Free to start — and the core stays open.</h3>
<p class="lead">
The full editor and real-time collaboration are <strong>free to start</strong>, and the
file format is open, forever. Later, well charge teams for the things teams actually need —
private org workspaces, SSO and compliance, hosted storage, and optional AI assistance. The
individual, open-source core isnt the thing we paywall.
<strong>No per-editor toll. No metered AI. No surprises.</strong>
</p>
{/* TODO(verify): point-in-time competitor pricing — Flux was ~$112158/editor/mo.
Re-verify before stating a hard number publicly (§17, §31.10). */}
<p class="contrast muted">
Some browser EDA tools charge over $100 per editor, per month. We wont.
The editor and the open file format are <strong>free</strong> — design entirely in your
browser, with your files stored locally on your own machine. When you want PCBJams
<strong>cloud</strong> — hosted storage, sync across your devices, and shared workspaces for
your team — thats the paid part. The open core stays free, and your local files are always
yours.
</p>
</div>
@ -41,10 +36,6 @@ const row = [
</SectionBand>
<style>
.contrast {
margin-top: 1rem;
font-style: italic;
}
.money-card p {
margin: 0.35rem 0 0;
font-size: 0.95rem;

View file

@ -1,23 +1,22 @@
---
import SectionBand from '../components/SectionBand.astro';
import DemoVideo from '../components/DemoVideo.astro';
import Icon from '../components/Icon.astro';
const subpoints = [
{
icon: 'icons/collab.svg',
title: 'Live cursors & presence',
body: 'See whos here and where theyre working.',
comingSoon: true,
},
{
icon: 'icons/yjs.svg',
title: 'Conflict-free editing',
body: 'CRDT sync (Yjs) merges everyones edits — no overwrite wars.',
body: 'CRDT sync merges everyones edits — no overwrite wars.',
comingSoon: false,
},
{
icon: 'icons/message.svg',
title: 'Pin a comment to a pad',
body: 'Review and resolve right on the canvas.',
comingSoon: true,
},
];
---
@ -44,11 +43,11 @@ const subpoints = [
{
subpoints.map((s) => (
<li class="subpoint">
<Icon name={s.icon} mode="img" size="1.6rem" alt="" />
<div>
<strong>{s.title}</strong>
<p class="muted">{s.body}</p>
</div>
<strong class="subpoint-title">
{s.title}
{s.comingSoon && <span class="badge">Coming soon</span>}
</strong>
<p class="muted">{s.body}</p>
</li>
))
}
@ -68,14 +67,30 @@ const subpoints = [
grid-template-columns: repeat(3, 1fr);
}
.subpoint {
padding-top: 0.85rem;
border-top: 2px solid var(--accent);
}
.subpoint-title {
display: flex;
gap: 0.75rem;
align-items: flex-start;
align-items: center;
gap: 0.5rem;
flex-wrap: wrap;
}
.subpoint p {
margin: 0.2rem 0 0;
margin: 0.3rem 0 0;
font-size: 0.95rem;
}
.badge {
font-family: var(--font-mono);
font-size: 0.7rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.04em;
color: var(--signal-400);
border: 1px solid color-mix(in srgb, var(--signal-400) 50%, transparent);
border-radius: var(--radius-full, 9999px);
padding: 0.1rem 0.5rem;
}
@media (max-width: 760px) {
.subpoints {
grid-template-columns: 1fr;

View file

@ -1,7 +1,6 @@
---
import SectionBand from '../components/SectionBand.astro';
import Chip from '../components/Chip.astro';
import Icon from '../components/Icon.astro';
const chips = [
'Open .kicad_pcb / .kicad_sch',
@ -12,40 +11,28 @@ const chips = [
---
<SectionBand id="open" labelledby="open-h2">
<div class="open-grid">
<div class="section-head open-copy">
<span class="eyebrow">No lock-in. No data hostage.</span>
<h2 id="open-h2">Design <em>and</em> collaborate in the browser — without surrendering your files.</h2>
<p class="lead">
Cloud EDA tools trap your designs in proprietary formats and clouds you cant leave.
Desktop open-source tools keep you free but strand you offline and solo. PCBJam refuses
the trade-off: <strong>real KiCad format</strong> in and out, <strong>self-host</strong>
it on your own server, run it <strong>offline as a PWA</strong>, and its
<strong>open source</strong>. Collaborate in our cloud when its convenient — and walk
away with every byte whenever you want.
</p>
<div class="cluster">
{chips.map((c) => <Chip label={c} />)}
</div>
<p class="reassure muted">
PCBJam rides KiCad — a project backed for decades by CERN, the KiCad Services Corp, and a
global community. This isnt a VC bet that vanishes when the runway ends.
</p>
</div>
<div class="open-art" aria-hidden="true">
<Icon name="icons/cloud.svg" mode="img" size="5rem" />
<Icon name="icons/github.svg" mode="mask" size="3rem" class="open-gh" />
<div class="section-head open-copy">
<span class="eyebrow">No lock-in. No data hostage.</span>
<h2 id="open-h2">Design <em>and</em> collaborate in the browser — without surrendering your files.</h2>
<p class="lead">
Cloud EDA tools trap your designs in proprietary formats and clouds you cant leave.
Desktop open-source tools keep you free but strand you offline and solo. PCBJam refuses
the trade-off: <strong>real KiCad format</strong> in and out, <strong>self-host</strong>
it on your own server, run it <strong>offline as a PWA</strong>, and its
<strong>open source</strong>. Collaborate in our cloud when its convenient — and walk
away with every byte whenever you want.
</p>
<div class="cluster">
{chips.map((c) => <Chip label={c} />)}
</div>
<p class="reassure muted">
PCBJam rides KiCad — a project backed for decades by CERN, the KiCad Services Corp, and a
global community. This isnt a VC bet that vanishes when the runway ends.
</p>
</div>
</SectionBand>
<style>
.open-grid {
display: grid;
grid-template-columns: 1.4fr 0.6fr;
gap: 2rem;
align-items: center;
}
.open-copy {
margin-bottom: 0;
}
@ -57,19 +44,4 @@ const chips = [
font-size: 0.9rem;
max-width: 40rem;
}
.open-art {
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
color: var(--accent);
}
@media (max-width: 820px) {
.open-grid {
grid-template-columns: 1fr;
}
.open-art {
display: none;
}
}
</style>

View file

@ -8,15 +8,15 @@ import Pillar from '../components/Pillar.astro';
<h2 id="pillars-h2">Three things that set PCBJam apart.</h2>
</div>
<div class="cards-3">
<Pillar title="Runs in a browser tab." icon="icons/responsive.svg" iconMode="img">
<Pillar title="Runs in a browser tab.">
Zero install, zero toolchain. Mac, Linux, Windows, Chromebook, iPad — if it has a
modern browser, it designs PCBs.
</Pillar>
<Pillar title="Truly multiplayer." icon="icons/collab.svg" iconMode="img">
<Pillar title="Truly multiplayer.">
Live cursors, presence, and conflict-free co-editing on the same board. Plus
pin-to-canvas comments for review.
</Pillar>
<Pillar title="Open & yours." icon="icons/github.svg" iconMode="mask">
<Pillar title="Open & yours.">
Real KiCad format in, real KiCad format out. Self-host it, run it offline as a PWA, or
use our cloud — your files are never held hostage.
</Pillar>

View file

@ -1,6 +1,5 @@
---
import SectionBand from '../components/SectionBand.astro';
import Placeholder from '../components/Placeholder.astro';
---
<SectionBand labelledby="pos-h3">
@ -12,10 +11,25 @@ import Placeholder from '../components/Placeholder.astro';
<strong>PCBJam is the only one in the middle.</strong>
</p>
</div>
{/* TODO(assets): build the quadrant/Venn graphic on the you-are-here motif (§4b.5). */}
<Placeholder
label="PRODUCE: positioning quadrant — Browser × Open × Multiplayer (§15)"
kind="image"
ratio="2 / 1"
<img
class="pos-map"
src="/graphics/positioning-quadrant.svg"
width="820"
height="600"
alt="Positioning map: PCBJam is the only PCB tool that is browser-native, open, and truly real-time multiplayer. Flux and EasyEDA are browser-based but proprietary; KiCanvas is browser and open but viewer-only; LibrePCB and KiCad are open but desktop-only; Altium 365 and OrCAD X are desktop and proprietary."
loading="lazy"
decoding="async"
/>
</SectionBand>
<style>
.pos-map {
display: block;
width: 100%;
max-width: 46rem;
height: auto;
margin-inline: auto;
border: 1px solid var(--border);
border-radius: var(--radius-lg);
}
</style>

View file

@ -8,7 +8,7 @@ const stats = [
{ value: 'Millions', label: 'KiCad users worldwide' },
{ value: 'Largest', label: 'open component & footprint library in EDA' },
{ value: '100%', label: 'open file format — your .kicad_pcb / .kicad_sch' },
{ value: 'Free', label: 'to start — no card, no per-seat toll' },
{ value: 'Free', label: 'to start — no credit card' },
];
---

View file

@ -225,6 +225,13 @@ main.wide {
padding-block: 0;
}
/* Only the hero waitlist form needs an anchor offset for the sticky header
the section anchors (#how-it-works, #open) already clear it via their own
top padding, so we don't touch global scroll behavior. */
#waitlist {
scroll-margin-top: 5rem;
}
/* Visually-hidden but accessible (labels, honeypot). */
.sr-only {
position: absolute;