open-design/apps/landing-page/public/community/index.html
Jane 82203fe4a7
fix(landing-page): community page brand mark + license + nav trim + twitter handle (#3222)
* fix(landing-page): trim community page nav + correct twitter handle

Two small corrections to the static `apps/landing-page/public/community/index.html` page served at https://open-design.ai/community/:

- Drop the `Skills` and `Design systems` shortcuts from the page-level
  top nav. The site-wide topbar already routes to the unified
  `/plugins/` hub (Templates / Skills / Systems / Craft are all
  faceted from there since PR #2880 / #2926 / #2958), so the
  Contributors page nav exposing two of those four facets out-of-
  context reads as inconsistent — visitors who clicked through were
  bypassing the hub. Keep `Ambassadors` (in-page anchor), `GitHub`,
  and the Discord pill; everything else in this list is a
  contributor-facing destination.

- Update the footer X / Twitter link from `x.com/nexu_io` to
  `x.com/nexudotio`. The `@nexudotio` handle is the active product
  account; `@nexu_io` was a stale earlier handle.

No JS / build-pipeline change — the page is static HTML served from
`public/`, so the diff is three lines.

* fix(landing-page): swap community page brand mark from letter "O" to logo image

The Contributors page top nav rendered a hand-rolled black circle
with a white "O" letter inside as the brand mark, which doesn't
match the rest of the site (homepage / sub-page header both use the
same `/logo.webp` image). On a Contributors page where the goal is
to read as a first-party Open Design property, having a different
brand mark in the corner reads as a different site.

Replace the `<span class="brand-mark">O</span>` literal with an
`<img src="/logo.webp">` and rewrite the local `.brand-mark` /
`.brand-mark img` rules to match the homepage's pattern: an
inline-flex 22×22 wrapper with a 5px-radius image inside (≈22%
of side, the same app-icon silhouette convention `globals.css`
uses for the homepage 44×44 mark, scaled down).

The asset is the same `/logo.webp` already shipped in
`public/`, so no new file is added.

* fix(landing-page): correct community footer license string MIT → Apache-2.0

The Contributors page footer rendered `© 2026 Open Design · MIT-licensed
· Built by contributors, in public.` — but Open Design has shipped under
Apache-2.0 since launch (the repo `LICENSE`, every page footer elsewhere
on the site, and the in-product chrome all say Apache-2.0). MIT was a
copy-paste leftover from an older draft and is materially wrong: the
two licenses differ on patent grants and trademark / attribution
mechanics, so showing the wrong one to a contributor reading the page
could shape downstream reuse decisions.

Single-string change: `MIT-licensed` → `Apache-2.0`. Confirmed via grep
that no other reference to MIT remains in the landing-page tree.

---------

Co-authored-by: Joey-nexu <joeylee12629@gmail.com>
2026-05-29 01:32:27 +00:00

875 lines
58 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#efe7d2" />
<title>Contributors — Open Design</title>
<link rel="preconnect" href="https://rsms.me/" />
<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
<style>
:root{
--paper:#efe7d2;
--paper-warm:#ece4cf;
--paper-dark:#ddd2b6;
--bone:#f7f1de;
--ink:#15140f;
--ink-soft:#2a2620;
--ink-mute:#5a5448;
--ink-faint:#8b8676;
--coral:#ed6f5c;
--coral-soft:#f08e7c;
--mustard:#e9b94a;
--olive:#6e7448;
--line:rgba(21,20,15,.16);
--line-soft:rgba(21,20,15,.08);
--shadow:0 30px 60px -30px rgba(21,20,15,.18);
--shadow-card:0 18px 40px -28px rgba(21,20,15,.32);
--sans:"Inter Tight", "Inter", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
--body:"Inter", -apple-system, system-ui, sans-serif;
--serif:"Playfair Display", "Iowan Old Style", "Times New Roman", serif;
--mono:"JetBrains Mono", "SF Mono", ui-monospace, Menlo, monospace;
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{background:var(--paper);color:var(--ink);font:16px/1.55 var(--body);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-feature-settings:"ss01","cv11"}
::selection{background:var(--coral);color:var(--bone)}
a{color:inherit;text-decoration:none}
img{display:block;max-width:100%}
/* --------- shared ---------- */
.wrap{max-width:1280px;margin:0 auto;padding:0 56px}
.kicker{font:600 11.5px/1 var(--mono);letter-spacing:.22em;text-transform:uppercase;color:var(--ink-mute)}
.kicker .dot{display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--coral);margin-right:10px;vertical-align:1px}
.h-display{font-family:var(--serif);font-weight:500;line-height:.98;letter-spacing:-.015em;color:var(--ink)}
.h-display em{font-style:italic;font-weight:500;color:var(--coral)}
.lead{font:400 19px/1.55 var(--body);color:var(--ink-soft);max-width:54ch}
.num{font:500 inherit/0.95 var(--mono);font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.btn{display:inline-flex;align-items:center;gap:10px;padding:14px 22px;border-radius:999px;font:500 14px/1 var(--sans);letter-spacing:.01em;border:1px solid transparent;transition:transform .15s ease,background .15s ease,color .15s ease}
.btn svg{width:14px;height:14px}
.btn-primary{background:var(--ink);color:var(--bone)}
.btn-primary:hover{background:var(--coral);color:var(--bone);transform:translateY(-1px)}
.btn-coral{background:var(--coral);color:var(--bone)}
.btn-coral:hover{background:var(--ink);color:var(--bone)}
.btn-ghost{background:transparent;color:var(--ink);border-color:var(--line)}
.btn-ghost:hover{border-color:var(--ink);background:var(--ink);color:var(--bone)}
/* --------- nav ---------- */
.nav{position:sticky;top:0;z-index:50;background:rgba(239,231,210,.86);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);border-bottom:1px solid var(--line-soft)}
.nav-inner{display:flex;align-items:center;justify-content:space-between;height:64px}
.brand{display:flex;align-items:center;gap:10px;font:600 14px/1 var(--sans);letter-spacing:-.01em}
.brand-mark{width:22px;height:22px;display:inline-flex;align-items:center;justify-content:center}
.brand-mark img{width:100%;height:100%;display:block;object-fit:contain;border-radius:5px}
.brand .sep{color:var(--ink-faint);margin:0 6px;font-weight:400}
.brand .crumb{color:var(--ink-mute);font-weight:500}
.nav-links{display:flex;gap:28px;align-items:center;font:500 13.5px/1 var(--sans)}
.nav-links a{color:var(--ink-soft);transition:color .15s}
.nav-links a:hover{color:var(--coral)}
.nav-links .pill{display:inline-flex;align-items:center;gap:8px;padding:8px 14px;border-radius:999px;background:var(--ink);color:var(--bone)}
.nav-links .pill:hover{background:var(--coral);color:var(--bone)}
/* --------- hero ---------- */
.hero{position:relative;padding:90px 0 110px;overflow:hidden}
.hero-grid{display:grid;grid-template-columns:1.45fr .9fr;gap:80px;align-items:center}
.hero-copy .kicker{margin-bottom:28px}
.hero h1{font-size:clamp(56px, 7.2vw, 104px);margin:14px 0 32px}
.hero .lead{font-size:21px;max-width:46ch;margin-bottom:40px}
.hero-cta{display:flex;gap:14px;flex-wrap:wrap;align-items:center}
.hero-meta{margin-top:54px;display:flex;gap:48px;border-top:1px solid var(--line-soft);padding-top:28px}
.hero-meta .item{display:flex;flex-direction:column;gap:4px}
.hero-meta .item .v{font:500 28px/1 var(--mono);font-variant-numeric:tabular-nums;letter-spacing:-.02em;color:var(--ink)}
.hero-meta .item .l{font:500 11px/1 var(--mono);letter-spacing:.22em;text-transform:uppercase;color:var(--ink-faint)}
.hero-card{position:relative;justify-self:center}
.hero-card .card-frame{width:300px;aspect-ratio:9/16;background:var(--bone);border:1px solid var(--line);border-radius:14px;box-shadow:var(--shadow);overflow:hidden;transform:rotate(2.5deg);transition:transform .35s ease}
.hero-card .card-frame:hover{transform:rotate(0deg) translateY(-6px)}
.hero-card .card-frame img{width:100%;height:100%;object-fit:cover}
.hero-card .card-tag{position:absolute;top:-14px;left:-30px;background:var(--coral);color:var(--bone);font:600 10.5px/1 var(--mono);letter-spacing:.22em;text-transform:uppercase;padding:8px 14px;border-radius:6px;transform:rotate(-4deg);box-shadow:var(--shadow-card)}
.hero-card .card-meta{position:absolute;bottom:-22px;right:-20px;background:var(--ink);color:var(--bone);padding:14px 18px;border-radius:10px;display:flex;flex-direction:column;gap:2px;box-shadow:var(--shadow-card);transform:rotate(-2deg)}
.hero-card .card-meta .h{font:600 13px/1.1 var(--sans)}
.hero-card .card-meta .s{font:500 10px/1 var(--mono);letter-spacing:.18em;text-transform:uppercase;color:var(--ink-faint)}
.hero-decor{position:absolute;right:-160px;top:60px;width:540px;height:540px;border-radius:50%;background:radial-gradient(circle at 30% 30%, rgba(237,111,92,.18), transparent 65%);pointer-events:none;z-index:0}
.hero-grid > *{position:relative;z-index:1}
/* --------- section header pattern ---------- */
.section{padding:96px 0}
.section-head{display:grid;grid-template-columns:1fr auto;align-items:end;gap:40px;margin-bottom:56px;padding-bottom:24px;border-bottom:1px solid var(--line)}
.section-head h2{font-size:clamp(40px,5vw,68px);max-width:18ch}
.section-head .right{font:400 15px/1.55 var(--body);color:var(--ink-mute);max-width:38ch;text-align:right;padding-bottom:12px}
.section-head .kicker{margin-bottom:20px;display:block}
/* --------- recent signal ---------- */
.signal{background:linear-gradient(180deg, var(--paper) 0%, var(--paper-warm) 100%)}
.signal-grid{display:grid;grid-template-columns:1.1fr 1fr;gap:48px}
.signal-feature{background:var(--ink);color:var(--bone);border-radius:18px;padding:42px;position:relative;overflow:hidden;display:flex;flex-direction:column;justify-content:space-between;min-height:520px}
.signal-feature::before{content:"";position:absolute;right:-120px;bottom:-160px;width:380px;height:380px;border-radius:50%;background:radial-gradient(circle, var(--coral) 0%, transparent 70%);opacity:.45}
.signal-feature .top{display:flex;justify-content:space-between;align-items:flex-start;position:relative;z-index:2}
.signal-feature .rank{font:500 13px/1 var(--mono);letter-spacing:.22em;text-transform:uppercase;color:var(--coral);display:flex;align-items:center;gap:10px}
.signal-feature .rank .badge{background:var(--coral);color:var(--ink);padding:5px 9px;border-radius:5px;font-weight:700;letter-spacing:.1em}
.signal-feature .week{font:500 12px/1 var(--mono);letter-spacing:.18em;text-transform:uppercase;color:var(--ink-faint)}
.signal-feature .body{position:relative;z-index:2;margin-top:48px}
.signal-feature .avatar{width:84px;height:84px;border-radius:50%;border:2px solid var(--coral);overflow:hidden;margin-bottom:24px}
.signal-feature .avatar img{width:100%;height:100%;object-fit:cover}
.signal-feature .name{font:500 38px/1.05 var(--serif);letter-spacing:-.01em;margin-bottom:6px}
.signal-feature .handle{font:500 13px/1 var(--mono);color:var(--ink-faint);margin-bottom:30px}
.signal-feature .quote{font-family:var(--serif);font-style:italic;font-size:22px;line-height:1.4;color:var(--paper);max-width:24ch;margin-bottom:34px;border-left:2px solid var(--coral);padding-left:18px}
.signal-feature .stats{padding:0;margin-top:auto}
.signal-feature .feature-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:24px;border-top:1px solid rgba(247,241,222,.12);padding-top:26px;position:relative;z-index:2}
.signal-feature .feature-stats .item .v{font:500 36px/1 var(--mono);font-variant-numeric:tabular-nums;letter-spacing:-.03em;color:var(--bone)}
.signal-feature .feature-stats .item .l{font:500 10.5px/1 var(--mono);letter-spacing:.22em;text-transform:uppercase;color:var(--ink-faint);margin-top:8px}
.signal-feature .feature-stats .item .v.coral{color:var(--coral)}
.signal.alltime{background:var(--paper)}
.signal-feature.alltime{background:linear-gradient(135deg, var(--ink) 0%, #2b2924 100%)}
.signal-feature.alltime::before{background:radial-gradient(circle, var(--coral) 0%, transparent 70%);opacity:.32}
.signal-feature.alltime .feature-stats{grid-template-columns:repeat(2,1fr)}
.leaderboard{display:flex;flex-direction:column}
.leaderboard-head{display:grid;grid-template-columns:40px 1fr 80px 80px 60px;gap:16px;padding:12px 0;border-bottom:1px solid var(--line);font:500 10.5px/1 var(--mono);letter-spacing:.22em;text-transform:uppercase;color:var(--ink-faint)}
.leaderboard-head span:nth-child(3),.leaderboard-head span:nth-child(4){text-align:right}
.row{display:grid;grid-template-columns:40px 1fr 80px 80px 60px;gap:16px;align-items:center;padding:14px 0;border-bottom:1px solid var(--line-soft);transition:background .15s}
.row:hover{background:var(--bone)}
.row .rk{font:500 13px/1 var(--mono);color:var(--ink-faint);font-variant-numeric:tabular-nums}
.row .who{display:flex;align-items:center;gap:14px}
.row .who img{width:36px;height:36px;border-radius:50%;background:var(--paper-dark)}
.row .who .n{font:500 15px/1.2 var(--sans);color:var(--ink)}
.row .who .h{font:400 12px/1 var(--mono);color:var(--ink-faint);margin-top:3px}
.row .v{text-align:right;font:500 16px/1 var(--mono);font-variant-numeric:tabular-nums;color:var(--ink)}
.row .v.coral{color:var(--coral)}
.row .arr{text-align:right;color:var(--ink-faint);transition:color .15s,transform .15s}
.row:hover .arr{color:var(--coral);transform:translateX(2px)}
/* --------- good first issues ---------- */
.issues{}
.issue-list{display:flex;flex-direction:column;border-top:1px solid var(--line)}
.issue{display:grid;grid-template-columns:64px 1fr auto auto;gap:24px;align-items:center;padding:26px 0;border-bottom:1px solid var(--line-soft);transition:padding .2s ease}
.issue:hover{padding-left:8px}
.issue:hover .title{color:var(--coral)}
.issue .num{font:500 28px/1 var(--mono);color:var(--ink-faint);font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.issue .body{display:flex;flex-direction:column;gap:8px}
.issue .title{font:500 22px/1.25 var(--serif);color:var(--ink);transition:color .15s;letter-spacing:-.005em}
.issue .meta{display:flex;gap:8px;flex-wrap:wrap}
.label{display:inline-flex;align-items:center;gap:6px;padding:5px 10px;border-radius:999px;font:500 11.5px/1 var(--mono);letter-spacing:.04em;background:var(--bone);border:1px solid var(--line-soft);color:var(--ink-mute)}
.label.good{background:#fff7e2;color:#7a5a00;border-color:rgba(122,90,0,.18)}
.label.docs{background:#e6f1e7;color:var(--olive);border-color:rgba(110,116,72,.25)}
.label.bug{background:#fde2dd;color:#a23a28;border-color:rgba(162,58,40,.2)}
.label.design{background:#f1e8fa;color:#5b3a8a;border-color:rgba(91,58,138,.2)}
.label.lang{background:transparent;border-color:var(--line);color:var(--ink-mute)}
.issue .lang{font:500 12px/1 var(--mono);color:var(--ink-faint);text-align:right;min-width:80px}
.issue .arr{color:var(--ink-faint);transition:color .15s,transform .15s}
.issue:hover .arr{color:var(--coral);transform:translateX(3px)}
.issues-foot{margin-top:36px;display:flex;justify-content:space-between;align-items:center;font:500 13px/1 var(--mono);color:var(--ink-mute)}
/* --------- onboarding steps ---------- */
.onboard{background:var(--ink);color:var(--paper);position:relative;overflow:hidden}
.onboard::before{content:"";position:absolute;top:-200px;left:-200px;width:500px;height:500px;border-radius:50%;background:radial-gradient(circle, rgba(237,111,92,.22) 0%, transparent 70%);pointer-events:none}
.onboard .section-head{border-bottom-color:rgba(247,241,222,.14)}
.onboard .section-head h2{color:var(--paper)}
.onboard .section-head h2 em{color:var(--coral)}
.onboard .section-head .right{color:var(--ink-faint)}
.onboard .kicker{color:var(--coral)}
.steps{display:grid;grid-template-columns:repeat(4,1fr);gap:0;border-top:1px solid rgba(247,241,222,.1);border-bottom:1px solid rgba(247,241,222,.1)}
.step{padding:42px 32px 48px;border-right:1px solid rgba(247,241,222,.1);position:relative}
.step:last-child{border-right:0}
.step .n{font:500 12px/1 var(--mono);letter-spacing:.22em;color:var(--coral);margin-bottom:18px}
.step h3{font:500 30px/1.1 var(--serif);letter-spacing:-.005em;margin-bottom:14px;color:var(--paper)}
.step h3 em{color:var(--coral);font-style:italic}
.step p{font:400 14.5px/1.55 var(--body);color:var(--ink-faint);margin-bottom:22px}
.step .ic{width:40px;height:40px;border-radius:50%;border:1px solid rgba(247,241,222,.2);display:grid;place-items:center;margin-bottom:24px;color:var(--coral)}
.step .ic svg{width:18px;height:18px}
.onboard-foot{margin-top:48px;display:flex;justify-content:center;gap:14px}
/* --------- maintainers ---------- */
.maintainers-grid{display:grid;grid-template-columns:repeat(2,minmax(320px,1fr));gap:24px;width:100%}
.m-card{background:var(--bone);border:1px solid var(--line-soft);border-radius:14px;padding:28px;display:flex;flex-direction:column;gap:18px;transition:transform .2s,box-shadow .2s}
.m-card:hover{transform:translateY(-4px);box-shadow:var(--shadow)}
.m-card .av{width:64px;height:64px;border-radius:50%;overflow:hidden;background:var(--paper-dark)}
.m-card .av img{width:100%;height:100%;object-fit:cover}
.m-card .n{font:500 19px/1.2 var(--serif);letter-spacing:-.005em}
.m-card .role{font:500 11.5px/1 var(--mono);letter-spacing:.18em;text-transform:uppercase;color:var(--coral);margin-top:6px}
.m-card .bio{font:400 13.5px/1.5 var(--body);color:var(--ink-mute);min-height:46px}
.m-card .links{display:flex;gap:14px;font:500 12.5px/1 var(--mono);color:var(--ink-faint);padding-top:18px;border-top:1px solid var(--line-soft)}
.m-card .links a:hover{color:var(--coral)}
.m-card .links svg{width:13px;height:13px;vertical-align:-2px;margin-right:5px}
/* --------- ambassadors ---------- */
.ambassadors{background:linear-gradient(180deg, var(--paper-warm) 0%, var(--paper) 100%)}
.amb-tagline{font-family:var(--serif);font-style:italic;font-weight:500;font-size:clamp(22px,2.4vw,30px);line-height:1.35;color:var(--ink-soft);max-width:34ch;margin:8px 0 0}
.amb-tagline em{color:var(--coral);font-style:italic}
.amb-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:0;border-top:1px solid var(--line);border-bottom:1px solid var(--line);background:var(--bone)}
.amb-col{padding:42px 36px 48px;border-right:1px solid var(--line-soft);position:relative;display:flex;flex-direction:column}
.amb-col:last-child{border-right:0}
.amb-col .n{font:500 12px/1 var(--mono);letter-spacing:.22em;color:var(--coral);margin-bottom:18px;text-transform:uppercase}
.amb-col h3{font:500 30px/1.1 var(--serif);letter-spacing:-.005em;margin-bottom:14px;color:var(--ink)}
.amb-col h3 em{color:var(--coral);font-style:italic}
.amb-col .lede{font:400 14.5px/1.55 var(--body);color:var(--ink-mute);margin-bottom:22px}
.amb-col ul{list-style:none;display:flex;flex-direction:column;gap:14px}
.amb-col li{display:grid;grid-template-columns:22px 1fr;gap:12px;align-items:start;font:400 14px/1.5 var(--body);color:var(--ink-soft)}
.amb-col li .ic{width:22px;height:22px;border-radius:50%;background:var(--paper-warm);display:grid;place-items:center;color:var(--coral);font:600 11px/1 var(--mono);margin-top:2px}
.amb-col li b{font-weight:600;color:var(--ink)}
.amb-foot{margin-top:48px;display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:20px}
.amb-foot .note{font:500 12.5px/1.5 var(--mono);color:var(--ink-faint);max-width:46ch;letter-spacing:.04em}
.amb-foot .cta{display:flex;gap:12px;flex-wrap:wrap}
.amb-more{margin-top:36px;border-top:1px solid var(--line-soft);padding-top:28px}
.amb-more summary{cursor:pointer;font:500 12.5px/1 var(--mono);letter-spacing:.18em;text-transform:uppercase;color:var(--ink-mute);list-style:none;display:inline-flex;align-items:center;gap:8px;padding:10px 16px;border-radius:999px;border:1px solid var(--line);background:var(--bone);transition:color .15s,border-color .15s}
.amb-more summary::-webkit-details-marker{display:none}
.amb-more summary::after{content:"+";font-weight:600;color:var(--coral)}
.amb-more[open] summary::after{content:""}
.amb-more summary:hover{color:var(--ink);border-color:var(--ink)}
.amb-more-grid{display:grid;grid-template-columns:1fr 1fr;gap:48px;margin-top:28px}
.amb-more-grid h4{font:500 11.5px/1 var(--mono);letter-spacing:.22em;text-transform:uppercase;color:var(--coral);margin-bottom:16px}
.amb-more-grid ul{list-style:disc;padding-left:18px;display:flex;flex-direction:column;gap:8px;font:400 13.5px/1.55 var(--body);color:var(--ink-mute)}
.amb-side{display:flex;flex-direction:column;align-items:flex-end;gap:20px;text-align:right}
.amb-side .amb-apply{font:600 14px/1 var(--sans);padding:16px 28px;letter-spacing:.01em;box-shadow:var(--shadow-card)}
.amb-side .amb-apply:hover{transform:translateY(-2px)}
.amb-side p{font:400 15px/1.55 var(--body);color:var(--ink-mute);max-width:38ch;margin:0}
/* --------- discord cta ---------- */
.discord{padding:120px 0}
.discord-card{background:var(--coral);color:var(--ink);border-radius:24px;padding:88px 72px;display:grid;grid-template-columns:1.4fr .8fr;gap:64px;align-items:center;position:relative;overflow:hidden;box-shadow:var(--shadow)}
.discord-card::after{content:"";position:absolute;top:-80px;right:-100px;width:340px;height:340px;border-radius:50%;background:radial-gradient(circle, rgba(247,241,222,.32) 0%, transparent 70%);pointer-events:none}
.discord-card .kicker{color:var(--ink-soft)}
.discord-card .kicker .dot{background:var(--ink)}
.discord-card h2{font-size:clamp(44px,5vw,68px);font-family:var(--serif);font-weight:500;line-height:1;letter-spacing:-.015em;margin:18px 0 22px}
.discord-card h2 em{font-style:italic}
.discord-card p{font:400 17px/1.55 var(--body);color:var(--ink-soft);max-width:42ch;margin-bottom:34px}
.discord-card .btn-primary{background:var(--ink);color:var(--coral)}
.discord-card .btn-primary:hover{background:var(--bone);color:var(--ink)}
.discord-card .btn-ghost{border-color:var(--ink);color:var(--ink)}
.discord-card .btn-ghost:hover{background:var(--ink);color:var(--coral)}
.discord-side{position:relative;z-index:2}
.discord-side .pop{font:500 12px/1 var(--mono);letter-spacing:.22em;text-transform:uppercase;color:var(--ink-soft);margin-bottom:22px}
.discord-side .stack{background:var(--ink);color:var(--bone);border-radius:14px;padding:22px}
.discord-side .stack .row-d{display:flex;align-items:center;gap:14px;padding:8px 0;font:500 13.5px/1 var(--sans)}
.discord-side .stack .row-d .dot-g{width:8px;height:8px;border-radius:50%;background:var(--coral)}
.discord-side .stack .row-d .h{font:400 11px/1 var(--mono);color:var(--ink-faint);margin-left:auto;text-transform:uppercase;letter-spacing:.12em}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.55}}
/* --------- footer ---------- */
.foot{padding:56px 0 64px;border-top:1px solid var(--line-soft);font:400 13px/1.5 var(--body);color:var(--ink-mute)}
.foot-inner{display:flex;justify-content:space-between;flex-wrap:wrap;gap:24px}
.foot a:hover{color:var(--coral)}
.foot .l{display:flex;gap:24px}
/* --------- responsive softening (desktop-first per brief) ---------- */
@media (max-width:1100px){
.wrap{padding:0 32px}
.hero-grid,.signal-grid,.discord-card{grid-template-columns:1fr;gap:48px}
.steps,.maintainers-grid{grid-template-columns:repeat(2,1fr);row-gap:56px}
.step:nth-child(2){border-right:0}
.section-head{grid-template-columns:1fr}
.section-head .right{text-align:left}
.amb-grid{grid-template-columns:1fr}
.amb-col{border-right:0;border-bottom:1px solid var(--line-soft)}
.amb-col:last-child{border-bottom:0}
.amb-more-grid{grid-template-columns:1fr;gap:32px}
.amb-side{align-items:flex-start;text-align:left}
}
@media (max-width:640px){
.wrap{padding:0 20px}
.nav-links a:not(.pill){display:none}
.nav-inner{height:58px}
.hero{padding:64px 0 78px}
.hero h1{font-size:54px}
.hero-card .card-frame{width:min(280px, 82vw)}
.section,.discord{padding:72px 0}
.section-head{margin-bottom:36px}
.steps,.maintainers-grid{grid-template-columns:1fr;row-gap:48px}
.step{border-right:0;padding:0 !important}
.leaderboard-head,.row{grid-template-columns:32px 1fr auto}
.leaderboard-head span:nth-child(3),.leaderboard-head span:nth-child(4),.row .v:not(.coral),.row .arr{display:none}
.amb-col{padding:32px 24px 36px}
}
/* loading skeletons */
.skel{background:linear-gradient(90deg, var(--paper-dark) 0%, var(--paper-warm) 50%, var(--paper-dark) 100%);background-size:200% 100%;animation:shimmer 1.5s infinite}
@keyframes shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}
</style>
</head>
<body>
<!-- ============ NAV ============ -->
<nav class="nav">
<div class="wrap nav-inner">
<a class="brand" href="https://open-design.ai/">
<span class="brand-mark"><img src="/logo.webp" alt="" width="22" height="22" /></span>
Open Design
<span class="sep">/</span>
<span class="crumb">Contributors</span>
</a>
<div class="nav-links">
<a href="#ambassadors">Ambassadors</a>
<a href="https://github.com/nexu-io/open-design">GitHub</a>
<a class="pill" href="#discord">
<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><path d="M19.27 5.33A18 18 0 0 0 14.72 4l-.2.4a13.7 13.7 0 0 0-5.04 0L9.27 4a18 18 0 0 0-4.54 1.33C2.4 8.94 1.78 12.45 2.09 15.9a18.4 18.4 0 0 0 5.6 2.83l1.13-1.55a11.6 11.6 0 0 1-1.78-.86l.44-.34a13 13 0 0 0 11.04 0l.44.34c-.55.33-1.16.61-1.78.86l1.13 1.55a18.3 18.3 0 0 0 5.6-2.83c.45-4.05-.5-7.53-2.64-10.57ZM9.5 14.07c-1.07 0-1.95-.99-1.95-2.21 0-1.22.86-2.22 1.95-2.22 1.1 0 1.97 1 1.95 2.22 0 1.22-.86 2.21-1.95 2.21Zm5 0c-1.07 0-1.95-.99-1.95-2.21 0-1.22.87-2.22 1.96-2.22 1.1 0 1.96 1 1.95 2.22 0 1.22-.86 2.21-1.96 2.21Z"/></svg>
Join Discord
</a>
</div>
</div>
</nav>
<!-- ============ HERO ============ -->
<section class="hero">
<div class="hero-decor"></div>
<div class="wrap hero-grid">
<div class="hero-copy">
<span class="kicker"><span class="dot"></span>Contributors · <span class="num">2026 cycle</span></span>
<h1 class="h-display">Open design <em>takes shape</em><br/>when you ship it.</h1>
<p class="lead">Open Design is built by people, in public. Skills, DESIGN.md systems, plugins, docs — every commit is a brushstroke. Pick an issue, send a PR, and earn a one-of-one honor card the moment you're merged.</p>
<div class="hero-cta">
<a class="btn btn-primary" href="#issues">
Pick a first issue
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
</a>
<a class="btn btn-ghost" href="#how">How contributing works</a>
<a class="btn btn-coral" href="#discord">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M19.27 5.33A18 18 0 0 0 14.72 4l-.2.4a13.7 13.7 0 0 0-5.04 0L9.27 4a18 18 0 0 0-4.54 1.33C2.4 8.94 1.78 12.45 2.09 15.9a18.4 18.4 0 0 0 5.6 2.83l1.13-1.55a11.6 11.6 0 0 1-1.78-.86l.44-.34a13 13 0 0 0 11.04 0l.44.34c-.55.33-1.16.61-1.78.86l1.13 1.55a18.3 18.3 0 0 0 5.6-2.83c.45-4.05-.5-7.53-2.64-10.57Z"/></svg>
Join the Discord
</a>
</div>
</div>
<div class="hero-card">
<span class="card-tag">Honor card · Giotto tier</span>
<div class="card-frame">
<img src="https://raw.githubusercontent.com/nexu-io/open-design/bot-cards/data/cards/dev-kp-eloper-signal-2026-05-26T03-19-40-361Z.png" alt="Open Design contributor honor card — @dev-kp-eloper, top 99.9%, Giotto tier" loading="eager"/>
</div>
<div class="card-meta">
<span class="h">Auto-minted on first merge</span>
<span class="s">PNG · shared on X</span>
</div>
</div>
</div>
</section>
<!-- ============ AMBASSADORS ============ -->
<section class="section ambassadors" id="ambassadors">
<div class="wrap">
<div class="section-head">
<div>
<span class="kicker"><span class="dot"></span>Open Design Ambassadors</span>
<h2 class="h-display">Be Open Design's <em>voice</em> in your city.</h2>
<p class="amb-tagline">Open a local atelier. Convene the meetups, the demos, the late-night critiques — the studio carries the work with budget, materials, and a line straight to the team.</p>
</div>
<div class="right amb-side">
<a class="btn btn-coral amb-apply" href="https://discord.gg/2p7Ajbxw3h" target="_blank" rel="noopener">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M19.27 5.33A18 18 0 0 0 14.72 4l-.2.4a13.7 13.7 0 0 0-5.04 0L9.27 4a18 18 0 0 0-4.54 1.33C2.4 8.94 1.78 12.45 2.09 15.9a18.4 18.4 0 0 0 5.6 2.83l1.13-1.55a11.6 11.6 0 0 1-1.78-.86l.44-.34a13 13 0 0 0 11.04 0l.44.34c-.55.33-1.16.61-1.78.86l1.13 1.55a18.3 18.3 0 0 0 5.6-2.83c.45-4.05-.5-7.53-2.64-10.57Z"/></svg>
Apply on Discord
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
</a>
<p>Ambassadors turn Open Design from a repository into something contributors can meet — in a room, with ink on the table and coffee gone cold.</p>
</div>
</div>
<div class="amb-grid">
<div class="amb-col">
<div class="n">I · Vocation</div>
<h3>Painters of <em>the local scene</em>.</h3>
<p class="lede">Designers, developers, organizers — the kind who already gather others. We give the gathering a flag.</p>
<ul>
<li><span class="ic">·</span><span><b>Local Atelier Host</b> — you keep a recurring meetup, study group, or late-night hack alive.</span></li>
<li><span class="ic">·</span><span><b>Online community lead</b> — Discord, WeChat, Telegram, X spaces.</span></li>
<li><span class="ic">·</span><span><b>Practising contributor or evangelist</b> — already shipping work, posting craft, ushering newcomers.</span></li>
<li><span class="ic">·</span><span><b>Comfortable carrying the name</b> — bound to the Code of Conduct, mindful of the brand.</span></li>
</ul>
</div>
<div class="amb-col">
<div class="n">II · Patronage</div>
<h3>What the <em>atelier</em> extends.</h3>
<p class="lede">Not a volunteer badge. A working bond — with budget, standing, and access.</p>
<ul>
<li><span class="ic">·</span><span><b>A page on the site</b> — portrait, city, biography, socials, the chronicle of your events.</span></li>
<li><span class="ic">·</span><span><b>First sight</b> — beta features, internal roadmap previews, releases ahead of the queue.</span></li>
<li><span class="ic">·</span><span><b>The atelier kit</b> — posters, slide decks, demo pieces, swag; a purse for venue, drinks, and photography.</span></li>
<li><span class="ic">·</span><span><b>A line to the studio</b> — private channel, monthly sync, a dedicated path for your feedback.</span></li>
<li><span class="ic">·</span><span><b>A way forward</b> — honor cards and tiers, with a path into regional lead, speaker, or paid community roles.</span></li>
</ul>
</div>
<div class="amb-col">
<div class="n">III · Covenant</div>
<h3>The <em>discipline</em> of the studio.</h3>
<p class="lede">A modest commitment, but binding. Extended absence folds into alumni status — the circle stays small and serious.</p>
<ul>
<li><span class="ic">·</span><span><b>Convene</b> at least one event per month or quarter — local or online.</span></li>
<li><span class="ic">·</span><span><b>Welcome the new hand</b> — usher newcomers through their first contribution.</span></li>
<li><span class="ic">·</span><span><b>Listen close</b> — gather honest feedback from users, designers, developers, teams.</span></li>
<li><span class="ic">·</span><span><b>Leave a record</b> — publish a recap after every gathering: attendance, photographs, links, leads.</span></li>
<li><span class="ic">·</span><span><b>Carry the name well</b> — hold to the Code of Conduct; no misuse of the mark, no deals signed on the studio's behalf.</span></li>
</ul>
</div>
</div>
</div>
</section>
<!-- ============ MAINTAINERS ============ -->
<section class="section">
<div class="wrap">
<div class="section-head">
<div>
<span class="kicker"><span class="dot"></span>Steering the ship</span>
<h2 class="h-display">The <em>maintainers</em>.</h2>
</div>
<p class="right">Maintainers protect the direction and quality of Open Design: they review contributions, keep the standard coherent, and make room for more contributors to earn their place in the project.</p>
</div>
<div class="maintainers-grid" id="maintainers-grid">
<article class="m-card">
<div class="av"><img src="https://github.com/Nagendhra-web.png" onerror="this.style.background='var(--ink)';this.removeAttribute('src')" alt=""/></div>
<div>
<div class="n" id="m-1-name">Nagendhra-web</div>
<div class="role" id="m-1-role">Maintainer</div>
</div>
<p class="bio" id="m-1-bio">Nagendhra brings a data engineer's instinct for production truth: find the failure, measure the edge case, and fix it properly. In Open Design, that shows up in deploy preflight work, asset-bundling hardening, and Windows fixes that make the project feel trustworthy when contributors ship.</p>
<div class="links">
<a href="https://github.com/Nagendhra-web" target="_blank"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 .5C5.7.5.5 5.7.5 12c0 5.1 3.3 9.4 7.8 10.9.6.1.8-.2.8-.6v-2c-3.2.7-3.9-1.5-3.9-1.5-.5-1.3-1.3-1.7-1.3-1.7-1.1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1 1.8 2.7 1.3 3.4 1 .1-.8.4-1.3.8-1.6-2.6-.3-5.3-1.3-5.3-5.7 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.5.1-3.2 0 0 1-.3 3.3 1.2.9-.3 2-.4 3-.4s2.1.1 3 .4c2.3-1.5 3.3-1.2 3.3-1.2.6 1.7.2 2.9.1 3.2.7.8 1.2 1.8 1.2 3.1 0 4.4-2.7 5.4-5.3 5.7.4.4.8 1.1.8 2.2v3.3c0 .3.2.7.8.6 4.5-1.5 7.8-5.8 7.8-10.9C23.5 5.7 18.3.5 12 .5z"/></svg>github</a>
</div>
</article>
<article class="m-card">
<div class="av"><img src="https://github.com/Sid-Qin.png" onerror="this.style.background='var(--coral)';this.removeAttribute('src')" alt=""/></div>
<div>
<div class="n" id="m-2-name">Sid-Qin</div>
<div class="role" id="m-2-role">Maintainer</div>
</div>
<p class="bio" id="m-2-bio">Sid is the generalist engineer with a designer's eye for detail: the kind of maintainer who notices both the broken CLI path and the crooked interaction affordance. In Open Design, Sid keeps export flows, plugin actions, Windows shims, MIME handling, and agent plumbing sharp enough for a community to build on.</p>
<div class="links">
<a href="https://github.com/Sid-Qin" target="_blank"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 .5C5.7.5.5 5.7.5 12c0 5.1 3.3 9.4 7.8 10.9.6.1.8-.2.8-.6v-2c-3.2.7-3.9-1.5-3.9-1.5-.5-1.3-1.3-1.7-1.3-1.7-1.1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1 1.8 2.7 1.3 3.4 1 .1-.8.4-1.3.8-1.6-2.6-.3-5.3-1.3-5.3-5.7 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.5.1-3.2 0 0 1-.3 3.3 1.2.9-.3 2-.4 3-.4s2.1.1 3 .4c2.3-1.5 3.3-1.2 3.3-1.2.6 1.7.2 2.9.1 3.2.7.8 1.2 1.8 1.2 3.1 0 4.4-2.7 5.4-5.3 5.7.4.4.8 1.1.8 2.2v3.3c0 .3.2.7.8.6 4.5-1.5 7.8-5.8 7.8-10.9C23.5 5.7 18.3.5 12 .5z"/></svg>github</a>
</div>
</article>
</div>
</div>
</section>
<!-- ============ ALL-TIME SIGNAL ============ -->
<section class="section signal alltime" id="alltime">
<div class="wrap">
<div class="section-head">
<div>
<span class="kicker"><span class="dot"></span>All-time signal</span>
<h2 class="h-display">The contributors with <em>deep roots</em>.</h2>
</div>
<p class="right">A long-running record of talented contributors who keep turning ideas, fixes, and craft into the shared Open Design standard.</p>
</div>
<div class="signal-grid">
<article class="signal-feature alltime">
<div class="top">
<div class="rank"><span class="badge">01</span> All-time contributor</div>
<div class="week">Repository history</div>
</div>
<div class="body">
<div class="avatar"><img id="feat-avatar-at" src="" alt="" /></div>
<div class="name" id="feat-name-at"></div>
<div class="handle" id="feat-handle-at"></div>
<p class="quote">The long tail matters: design systems, docs fixes, examples, and small repairs are how an open design language becomes dependable.</p>
</div>
<div class="feature-stats">
<div class="item"><div class="v coral" id="feat-commits-at"></div><div class="l">Commits</div></div>
<div class="item"><div class="v">#01</div><div class="l">External rank</div></div>
</div>
</article>
<div class="leaderboard">
<div class="leaderboard-head">
<span>#</span>
<span>Contributor</span>
<span>Commits</span>
<span>Rank</span>
<span></span>
</div>
<div id="leaderboard-rows-at">
<div class="row"><span class="rk">02</span><span class="who"><div class="skel" style="width:36px;height:36px;border-radius:50%"></div><div><div class="n skel" style="width:120px;height:14px"></div><div class="h skel" style="width:80px;height:10px;margin-top:6px"></div></div></span><span class="v"></span><span class="v coral"></span><span class="arr"></span></div>
<div class="row"><span class="rk">03</span><span class="who"><div class="skel" style="width:36px;height:36px;border-radius:50%"></div><div><div class="n skel" style="width:140px;height:14px"></div><div class="h skel" style="width:80px;height:10px;margin-top:6px"></div></div></span><span class="v"></span><span class="v coral"></span><span class="arr"></span></div>
<div class="row"><span class="rk">04</span><span class="who"><div class="skel" style="width:36px;height:36px;border-radius:50%"></div><div><div class="n skel" style="width:120px;height:14px"></div><div class="h skel" style="width:80px;height:10px;margin-top:6px"></div></div></span><span class="v"></span><span class="v coral"></span><span class="arr"></span></div>
<div class="row"><span class="rk">05</span><span class="who"><div class="skel" style="width:36px;height:36px;border-radius:50%"></div><div><div class="n skel" style="width:120px;height:14px"></div><div class="h skel" style="width:80px;height:10px;margin-top:6px"></div></div></span><span class="v"></span><span class="v coral"></span><span class="arr"></span></div>
</div>
</div>
</div>
</div>
</section>
<!-- ============ RECENT SIGNAL ============ -->
<section class="section signal weekly" id="signal">
<div class="wrap">
<div class="section-head">
<div>
<span class="kicker"><span class="dot"></span>Recent signal</span>
<h2 class="h-display">Ten contributors with <em>recent momentum</em>.</h2>
</div>
<p class="right">A snapshot of sharp contributors landing PRs, improving the product, and making Open Design feel alive.</p>
</div>
<div class="signal-grid">
<article class="signal-feature" id="feature-card">
<div class="top">
<div class="rank"><span class="badge">01</span> A recent leader</div>
<div class="week">Snapshot</div>
</div>
<div class="body">
<div class="avatar"><img id="feat-avatar" src="" alt="" /></div>
<div class="name" id="feat-name"></div>
<div class="handle" id="feat-handle"></div>
<p class="quote" id="feat-blurb">A contributor taking the lead with focused, generous work.</p>
<p class="quote-prs" id="feat-prs-list" style="margin-top:14px;font-family:var(--body);font-style:normal;font-size:14px;line-height:1.55;color:rgba(255,255,255,.62);font-weight:400;letter-spacing:0"></p>
</div>
<div class="feature-stats">
<div class="item"><div class="v coral" id="feat-rank">#01</div><div class="l">Rank</div></div>
<div class="item"><div class="v" id="feat-prs"></div><div class="l">Recent PRs</div></div>
</div>
</article>
<div class="leaderboard">
<div class="leaderboard-head">
<span>#</span>
<span>Contributor</span>
<span>PRs</span>
<span>Rank</span>
<span></span>
</div>
<div id="leaderboard-rows">
<div class="row"><span class="rk">02</span><span class="who"><div class="skel" style="width:36px;height:36px;border-radius:50%"></div><div><div class="n skel" style="width:120px;height:14px"></div><div class="h skel" style="width:80px;height:10px;margin-top:6px"></div></div></span><span class="v"></span><span class="v coral"></span><span class="arr"></span></div>
<div class="row"><span class="rk">03</span><span class="who"><div class="skel" style="width:36px;height:36px;border-radius:50%"></div><div><div class="n skel" style="width:140px;height:14px"></div><div class="h skel" style="width:80px;height:10px;margin-top:6px"></div></div></span><span class="v"></span><span class="v coral"></span><span class="arr"></span></div>
<div class="row"><span class="rk">04</span><span class="who"><div class="skel" style="width:36px;height:36px;border-radius:50%"></div><div><div class="n skel" style="width:120px;height:14px"></div><div class="h skel" style="width:80px;height:10px;margin-top:6px"></div></div></span><span class="v"></span><span class="v coral"></span><span class="arr"></span></div>
<div class="row"><span class="rk">05</span><span class="who"><div class="skel" style="width:36px;height:36px;border-radius:50%"></div><div><div class="n skel" style="width:120px;height:14px"></div><div class="h skel" style="width:80px;height:10px;margin-top:6px"></div></div></span><span class="v"></span><span class="v coral"></span><span class="arr"></span></div>
</div>
</div>
</div>
</div>
</section>
<!-- ============ GOOD FIRST ISSUES ============ -->
<section class="section issues" id="issues">
<div class="wrap">
<div class="section-head">
<div>
<span class="kicker"><span class="dot"></span>Pick your first contribution</span>
<h2 class="h-display">Open issues, <em>tagged for you</em>.</h2>
</div>
<p class="right">Live from <span class="num">label:&ldquo;good first issue&rdquo;</span> on the Open Design repo. Comment on an issue to claim it — a maintainer will assign it within a day.</p>
</div>
<div class="issue-list" id="issue-list">
<div class="issue">
<span class="num"></span>
<div class="body"><div class="title skel" style="height:24px;width:60%"></div><div class="meta"><span class="label good">good first issue</span></div></div>
<span class="lang"></span>
<span class="arr"></span>
</div>
<div class="issue">
<span class="num"></span>
<div class="body"><div class="title skel" style="height:24px;width:50%"></div><div class="meta"><span class="label good">good first issue</span></div></div>
<span class="lang"></span>
<span class="arr"></span>
</div>
<div class="issue">
<span class="num"></span>
<div class="body"><div class="title skel" style="height:24px;width:65%"></div><div class="meta"><span class="label good">good first issue</span></div></div>
<span class="lang"></span>
<span class="arr"></span>
</div>
</div>
<div class="issues-foot">
<span>Showing first <span class="num" id="issue-count"></span> open good-first-issues</span>
<a href="https://github.com/nexu-io/open-design/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22" target="_blank" rel="noopener" style="color:var(--coral)">See all on GitHub →</a>
</div>
</div>
</section>
<!-- ============ ONBOARDING — HOW TO BECOME A CONTRIBUTOR ============ -->
<section class="section onboard" id="how">
<div class="wrap">
<div class="section-head">
<div>
<span class="kicker"><span class="dot"></span>Four steps · any skill level</span>
<h2 class="h-display">From zero to <em>merged</em>, in an afternoon.</h2>
</div>
<p class="right">Whether you're a designer, a writer, an engineer, or someone who just spotted a typo — there's a contribution shape for you. Here's the path.</p>
</div>
<div class="steps">
<div class="step">
<div class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.35-4.35"/></svg></div>
<div class="n">Step 01</div>
<h3>Find a <em>spark</em>.</h3>
<p>Browse the good-first-issues list above, or open a new issue describing something you'd improve. Designers — DESIGN.md systems are the easiest entry.</p>
</div>
<div class="step">
<div class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M14 4H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V9zM14 4v5h5"/></svg></div>
<div class="n">Step 02</div>
<h3>Open a <em>draft</em> PR.</h3>
<p>Fork, branch, push. Mark it draft — it signals you want feedback early. Mention which issue it closes. The CI is fast; bot-cards stays on its own branch.</p>
</div>
<div class="step">
<div class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg></div>
<div class="n">Step 03</div>
<h3>Review with <em>a human</em>.</h3>
<p>A maintainer reviews within 24h. We're kind, specific, and never gatekeep. If you're stuck, drop the PR link in Discord #help.</p>
</div>
<div class="step">
<div class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M3 12l2 2 4-4M3 6l2 2 4-4M3 18l2 2 4-4M13 6h8M13 12h8M13 18h8"/></svg></div>
<div class="n">Step 04</div>
<h3>Merge → <em>card</em>.</h3>
<p>The bot mints your honor card the moment you're merged and pushes it to the bot-cards branch. Share it on X with #openDesign — we repost the best ones.</p>
</div>
</div>
<div class="onboard-foot">
<a class="btn btn-coral" href="https://github.com/nexu-io/open-design/blob/main/CONTRIBUTING.md">
Read the contributing guide
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
</a>
<a class="btn btn-ghost" href="https://github.com/nexu-io/open-design/blob/main/CODE_OF_CONDUCT.md" style="color:var(--paper);border-color:rgba(247,241,222,.25)">Code of Conduct</a>
</div>
</div>
</section>
<!-- ============ DISCORD CTA ============ -->
<section class="discord" id="discord">
<div class="wrap">
<div class="discord-card">
<div>
<span class="kicker"><span class="dot"></span>Where contributors hang out</span>
<h2>Talk to the people who'll <em>review your PR</em>.</h2>
<p>Our Discord is where contributors show shipped work, discuss plugins, join beta tests, and get help when a PR gets stuck. No fake activity counters — just the channels people can actually use.</p>
<div style="display:flex;gap:14px;flex-wrap:wrap">
<a class="btn btn-primary" href="https://discord.gg/3C6EWXbdQQ">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M19.27 5.33A18 18 0 0 0 14.72 4l-.2.4a13.7 13.7 0 0 0-5.04 0L9.27 4a18 18 0 0 0-4.54 1.33C2.4 8.94 1.78 12.45 2.09 15.9a18.4 18.4 0 0 0 5.6 2.83l1.13-1.55a11.6 11.6 0 0 1-1.78-.86l.44-.34a13 13 0 0 0 11.04 0l.44.34c-.55.33-1.16.61-1.78.86l1.13 1.55a18.3 18.3 0 0 0 5.6-2.83c.45-4.05-.5-7.53-2.64-10.57Z"/></svg>
Join the Discord
</a>
<a class="btn btn-ghost" href="https://github.com/nexu-io/open-design/discussions">GitHub Discussions</a>
</div>
</div>
<div class="discord-side">
<div class="pop">Community Discord</div>
<div class="stack">
<div class="row-d"><span class="dot-g"></span>#showcase<span class="h">work shipped</span></div>
<div class="row-d"><span class="dot-g"></span>#plugin<span class="h">builders</span></div>
<div class="row-d"><span class="dot-g"></span>#beta-test<span class="h">early feedback</span></div>
<div class="row-d"><span class="dot-g"></span>#help<span class="h">unstuck</span></div>
</div>
</div>
</div>
</div>
</section>
<!-- ============ FOOTER ============ -->
<footer class="foot">
<div class="wrap foot-inner">
<span>© 2026 Open Design · Apache-2.0 · Built by contributors, in public.</span>
<div class="l">
<a href="https://github.com/nexu-io/open-design">GitHub</a>
<a href="https://discord.gg/3C6EWXbdQQ">Discord</a>
<a href="https://x.com/nexudotio">X / Twitter</a>
<a href="https://open-design.ai/">open-design.ai</a>
</div>
</div>
</footer>
<!-- =================== Page data + GitHub helpers =================== -->
<script>
/**
* Open Design — Contributors page
* Open Design — Contributors page
* Leaderboards render from curated project records. GitHub calls hydrate
* good-first issues and maintainer profile details only.
*/
const REPO = 'nexu-io/open-design';
const API = (window.OPEN_DESIGN_API || 'https://api.github.com');
const HEADERS = (() => {
const h = { 'Accept': 'application/vnd.github+json', 'X-GitHub-Api-Version': '2022-11-28' };
if (window.GITHUB_TOKEN) h['Authorization'] = 'Bearer ' + window.GITHUB_TOKEN;
return h;
})();
/* Open Design core team and internal accounts. Lowercased GitHub logins. */
const CORE_TEAM = new Set([
'pftom','mrcfps','sophia','ashleyashli','qiongyu1999','zoeforfun',
'perishcode','nettee','anthhub','siri-ray','lefarcen',
'alchemistklk','shangxinyu1','joeylee12629-star','tuola-waj',
'leilei926524-tech','nagendhra-web','sid-qin','chaoxiaoche'
].map(s => s.toLowerCase()));
function isCore(login){ return login && CORE_TEAM.has(String(login).toLowerCase()); }
const BOT_LOGINS = new Set(['open-design-bot','opendesign-bot','nexu-bot','open-design-bot[bot]']);
/* Whole-token match on bot/cursor/agent so real logins like
'agentina', 'cursorsmith', 'robothai' are not silently dropped.
Token boundaries are start, end, '-', or '_'. */
const BOT_TOKEN_RE = /(?:^|[-_])(?:bot|cursor|agent)(?:$|[-_])/;
function isBot(c){
if (!c) return false;
if (c.type === 'Bot') return true;
const login = String(c.login || '').toLowerCase();
if (!login) return false;
if (login.endsWith('[bot]')) return true;
if (BOT_TOKEN_RE.test(login)) return true;
return BOT_LOGINS.has(login);
}
function isExcluded(c){
const login = c && c.login;
return !login || isCore(login) || isBot(c);
}
const RANKING_SNAPSHOT = {
generatedAt: '2026-05-26T12:25:59Z',
source: 'Curated contributor records for the Open Design community page.',
filters: ['core maintainers', 'known internal staff', 'type:Bot', '[bot] suffix', 'whole-token match: bot / cursor / agent'],
weekly: [
{ login:'bulai0408', avatar:'https://avatars.githubusercontent.com/u/31983330?v=4', prs:19, lastMerged:'2026-05-26', examples:[{number:2006,title:'fix(daemon): fail disallowed connector tool selections'},{number:2331,title:'fix(web): align HomeHero prompt overlay metrics'}] },
{ login:'522700967-wq', avatar:'https://avatars.githubusercontent.com/u/270050048?v=4', prs:14, lastMerged:'2026-05-26', examples:[{number:2958,title:'feat(landing-page): plugin detail page interactive preview + share dialog'},{number:2880,title:'fix(landing-page): copy example.html sibling assets in post-build'}] },
{ login:'YUHAO-corn', avatar:'https://avatars.githubusercontent.com/u/201702441?v=4', prs:10, lastMerged:'2026-05-26', examples:[{number:2971,title:'fix(web): align draw note enter action'},{number:2036,title:'fix(plugins): reject symlinked plugin assets'}] },
{ login:'xxiaoxiong', avatar:'https://avatars.githubusercontent.com/u/27723864?v=4', prs:10, lastMerged:'2026-05-26', examples:[{number:2932,title:'fix: synchronously update URL when creating new conversation to prevent route-sync conflict'},{number:2931,title:'fix: re-activate srcDoc transport when exiting Edit mode to prevent blank preview'}] },
{ login:'YOMXXX', avatar:'https://avatars.githubusercontent.com/u/18409951?v=4', prs:10, lastMerged:'2026-05-26', examples:[{number:2419,title:'feat(daemon): structured diagnostics for agent connection test results'},{number:2576,title:'fix(web): route chat file links to workspace preview instead of new window'}] },
{ login:'portseif', avatar:'https://avatars.githubusercontent.com/u/13489304?v=4', prs:9, lastMerged:'2026-05-25', examples:[{number:2847,title:'Capture native Swift source in the GitHub design import'},{number:2848,title:'Polish the design system review panel'}] },
{ login:'leessju', avatar:'https://avatars.githubusercontent.com/u/40141791?v=4', prs:7, lastMerged:'2026-05-26', examples:[{number:2844,title:'fix(web): live-update preview during Comment mode'},{number:2839,title:'fix(web): preserve chat composer drafts across refreshes'}] },
{ login:'GHX5T-SOL', avatar:'https://avatars.githubusercontent.com/u/200635707?v=4', prs:7, lastMerged:'2026-05-23', examples:[{number:2483,title:'Create design-system conversations from New action'},{number:2491,title:'fix(web): retry failed chat runs without duplicating user message'}] },
{ login:'neogenix', avatar:'https://avatars.githubusercontent.com/u/141967?v=4', prs:6, lastMerged:'2026-05-26', examples:[{number:2311,title:'chore(deps): upgrade express 4 -> 5 in daemon'},{number:2305,title:'chore(e2e): improve test framework quality'}] },
{ login:'prantikmedhi', avatar:'https://avatars.githubusercontent.com/u/140103052?v=4', prs:5, lastMerged:'2026-05-26', examples:[{number:2940,title:'fix: keep raw HTML source out of artifact chat prose'},{number:1556,title:'fix: hide preview chrome in source view'}] }
],
allTime: [
{ login:'bulai0408', avatar:'https://avatars.githubusercontent.com/u/31983330?v=4', commits:37, lastMerged:'long-running contributor' },
{ login:'Nicholas-Xiong', avatar:'https://github.com/Nicholas-Xiong.png', commits:35, lastMerged:'long-running contributor' },
{ login:'YUHAO-corn', avatar:'https://avatars.githubusercontent.com/u/201702441?v=4', commits:34, lastMerged:'long-running contributor' },
{ login:'leessju', avatar:'https://avatars.githubusercontent.com/u/40141791?v=4', commits:16, lastMerged:'long-running contributor' },
{ login:'prantikmedhi', avatar:'https://avatars.githubusercontent.com/u/140103052?v=4', commits:15, lastMerged:'long-running contributor' },
{ login:'522700967-wq', avatar:'https://avatars.githubusercontent.com/u/270050048?v=4', commits:14, lastMerged:'long-running contributor' },
{ login:'mturac', avatar:'https://avatars.githubusercontent.com/u/345446?v=4', commits:13, lastMerged:'long-running contributor' },
{ login:'Mason', avatar:'https://github.com/Mason.png', commits:12, lastMerged:'long-running contributor' },
{ login:'portseif', avatar:'https://avatars.githubusercontent.com/u/13489304?v=4', commits:10, lastMerged:'long-running contributor' },
{ login:'GHX5T-SOL', avatar:'https://avatars.githubusercontent.com/u/200635707?v=4', commits:8, lastMerged:'long-running contributor' }
]
};
async function gh(path) {
const res = await fetch(`${API}${path}`, { headers: HEADERS });
if (!res.ok) throw new Error(`GitHub ${path}${res.status}`);
return res.json();
}
function fmt(n){ return n == null ? '—' : (n >= 10000 ? (n/1000).toFixed(1)+'k' : n.toLocaleString()) }
function pad2(n){ return (n<10?'0':'')+n }
function leaderboardRows(list, metricKey, metricLabel){
return list.slice(1).map((c,i) => `
<a class="row" href="https://github.com/${c.login}" target="_blank" rel="noopener" title="${escapeHtml(metricLabel)} · rank ${pad2(i+2)}">
<span class="rk">${pad2(i+2)}</span>
<span class="who">
<img src="${c.avatar}" alt="${c.login}" loading="lazy" onerror="this.style.visibility='hidden'"/>
<span><span class="n">${c.login}</span><span class="h">@${c.login}</span></span>
</span>
<span class="v">${fmt(c[metricKey])}</span>
<span class="v coral">#${pad2(i+2)}</span>
<span class="arr">→</span>
</a>`).join('');
}
function exampleCopy(c){
return (c.examples || []).slice(0,2).map(pr => `#${pr.number} ${pr.title}`).join(' · ');
}
/* --------- weekly top 10 --------- */
async function loadWeeklyTop(){
const ranked = RANKING_SNAPSHOT.weekly.filter(c => !isExcluded(c));
const f = ranked[0];
if (!f) return;
document.getElementById('feat-avatar').src = f.avatar;
document.getElementById('feat-avatar').alt = f.login;
setText('feat-name', f.login);
setText('feat-handle', '@' + f.login + ' · recent contribution');
setText('feat-blurb', `${f.login} has set the pace with ${f.prs} merged PR${f.prs === 1 ? '' : 's'} and the kind of steady craft that keeps Open Design moving.`);
setText('feat-prs-list', exampleCopy(f));
setText('feat-rank', '#01');
setText('feat-prs', f.prs);
document.getElementById('leaderboard-rows').innerHTML = leaderboardRows(ranked, 'prs', 'Merged PRs');
}
/* --------- all-time top 10 --------- */
async function loadAllTimeTop(){
const top = RANKING_SNAPSHOT.allTime.filter(c => !isExcluded(c));
const f = top[0];
if (!f) return;
document.getElementById('feat-avatar-at').src = f.avatar;
document.getElementById('feat-avatar-at').alt = f.login;
setText('feat-name-at', f.login);
setText('feat-handle-at', '@' + f.login + ' · deep contributor signal');
setText('feat-commits-at', fmt(f.commits));
document.getElementById('leaderboard-rows-at').innerHTML = leaderboardRows(top, 'commits', 'Commits');
}
/* --------- good first issues --------- */
async function loadGoodFirstIssues(){
try {
const r = await gh(`/search/issues?q=repo:${REPO}+is:issue+is:open+label:%22good+first+issue%22&sort=created&order=desc&per_page=8`);
const items = r.items || [];
setText('issue-count', items.length);
if (!items.length){
document.getElementById('issue-list').innerHTML = '<div class="issue" style="color:var(--ink-faint);padding:36px 0">No open good-first-issues right now. Check back tomorrow, or open one yourself ↗</div>';
return;
}
const html = items.map((it,i) => {
const lang = inferLang(it.title);
return `
<a class="issue" href="${it.html_url}" target="_blank" rel="noopener">
<span class="num">${pad2(i+1)}</span>
<div class="body">
<div class="title">${escapeHtml(it.title)}</div>
<div class="meta">
<span class="label good">good first issue</span>
${(it.labels||[]).filter(l=>l.name!=='good first issue').slice(0,3).map(l=>`<span class="label ${inferLabelClass(l.name)}">${escapeHtml(l.name)}</span>`).join('')}
</div>
</div>
<span class="lang">${lang}</span>
<span class="arr">→</span>
</a>`;
}).join('');
document.getElementById('issue-list').innerHTML = html;
} catch(e){
console.warn('issues failed', e);
setText('issue-count', '—');
const list = document.getElementById('issue-list');
if (list) list.innerHTML = '<a class="issue" href="https://github.com/nexu-io/open-design/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22" target="_blank" rel="noopener"><span class="num">—</span><div class="body"><div class="title">GitHub rate limit reached in preview. Open the live good-first-issue search on GitHub.</div><div class="meta"><span class="label good">good first issue</span><span class="label docs">live GitHub search</span></div></div><span class="lang">WEB</span><span class="arr">→</span></a>';
}
}
function inferLabelClass(name){
const n = (name||'').toLowerCase();
if (n.includes('docs')||n.includes('doc')) return 'docs';
if (n.includes('bug')) return 'bug';
if (n.includes('design')||n.includes('ui')) return 'design';
return 'lang';
}
function inferLang(title){
const t = (title||'').toLowerCase();
if (t.includes('typescript')||t.includes('.ts')) return 'TS';
if (t.includes('python')) return 'PY';
if (t.includes('css')||t.includes('html')||t.includes('design')) return 'CSS';
if (t.includes('docs')||t.includes('readme')) return 'MD';
return 'JS/TS';
}
/* --------- maintainers (real GitHub profiles) --------- */
const MAINTAINERS = ['Nagendhra-web', 'Sid-Qin'];
async function loadMaintainers(){
await Promise.all(MAINTAINERS.map(async (login, i) => {
try {
const u = await gh(`/users/${login}`);
const idx = i + 1;
if (u.name) setText(`m-${idx}-name`, u.name);
// Keep the curated maintainer story visible; profile bios are too short for this page.
} catch (e) { /* leave the static fallback */ }
}));
}
/* --------- helpers --------- */
function setText(id, v){ const el = document.getElementById(id); if (el && v != null) el.textContent = v; }
function escapeHtml(s){ return String(s||'').replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c])); }
/* --------- boot --------- */
(async function(){
await Promise.all([ loadWeeklyTop(), loadAllTimeTop(), loadGoodFirstIssues(), loadMaintainers() ]);
})();
</script>
</body>
</html>