hlassiege/panopliepublic Fork
⑂ 968cd0f
Commits
⬇ Clone ▾
git clone https://git.rickub.com/hlassiege/panoplie.git
git clone ssh://git@rickub.com/hlassiege/panoplie.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP

feat: add animated catalog diagram, open source note and rickub icon to the site hero

hlassiege committed 2026-11-07T15:59:51+01:00 Browse files
968cd0f parent: 7111c7f
modified site/public/index.html +141 -6
@@ -37,17 +37,152 @@
3737 <a href="#how">How it works</a>
3838 <a href="#try">Try it</a>
3939 </nav>
40- <a class="btn btn-ink btn-sm" href="https://rickub.com/hlassiege/skilly">Source code</a>
40+ <a class="btn btn-ink btn-sm" href="https://rickub.com/hlassiege/skilly"><svg class="btn-icon" viewBox="0 0 64 64" aria-hidden="true"><path d="M32 8 A24 24 0 1 1 12 44"/><path d="M32 18 A14 14 0 1 0 46 32"/><circle cx="32" cy="32" r="6.5"/></svg>Source code</a>
4141 </header>
4242
4343 <main id="main">
4444 <section class="hero">
45- <h1>Stop copying skills from project to&nbsp;project.</h1>
46- <p class="lead">One catalog for your skills, rules and MCP servers.</p>
47- <div class="actions">
48- <a class="btn btn-ink" href="#try">Try it</a>
49- <a class="btn btn-line" href="https://rickub.com/hlassiege/skilly">Source code</a>
45+ <div class="hero-copy">
46+ <h1>Stop copying skills from project to&nbsp;project.</h1>
47+ <p class="lead">One catalog for your skills, rules and MCP servers.</p>
48+ <div class="actions">
49+ <a class="btn btn-ink" href="#try">Try it</a>
50+ <a class="btn btn-line" href="https://rickub.com/hlassiege/skilly"><svg class="btn-icon" viewBox="0 0 64 64" aria-hidden="true"><path d="M32 8 A24 24 0 1 1 12 44"/><path d="M32 18 A14 14 0 1 0 46 32"/><circle cx="32" cy="32" r="6.5"/></svg>Source code</a>
51+ </div>
52+ <p class="perk">
53+ <svg viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7"/></svg>
54+ Free and open source
55+ </p>
5056 </div>
57+
58+ <!-- The hub: sources flow into one catalog, the catalog flows out to each project.
59+ The static drawing is the final state; everything in .fx is SMIL motion on one 8s clock
60+ (same dur everywhere, timed with keyTimes), hidden when reduced motion is requested. -->
61+ <figure class="hub">
62+ <svg viewBox="0 0 480 500" role="img" aria-label="Skills from ~/.claude, Anthropic and git repos go into one catalog, then out to each project">
63+ <defs>
64+ <path id="hub-in1" d="M80 50 C80 100 200 100 200 150"/>
65+ <path id="hub-in2" d="M240 50 L240 150"/>
66+ <path id="hub-in3" d="M400 50 C400 100 280 100 280 150"/>
67+ <path id="hub-out1" d="M200 310 C200 362 80 360 80 412"/>
68+ <path id="hub-out2" d="M240 310 L240 412"/>
69+ <path id="hub-out3" d="M280 310 C280 362 400 360 400 412"/>
70+ </defs>
71+
72+ <g class="hub-lines">
73+ <use href="#hub-in1"/><use href="#hub-in2"/><use href="#hub-in3"/>
74+ <use href="#hub-out1"/><use href="#hub-out2"/><use href="#hub-out3"/>
75+ </g>
76+
77+ <!-- travelling items, drawn under the cards so they slide in and out of them -->
78+ <g class="fx">
79+ <g class="hub-dot" opacity="0">
80+ <circle r="9"/><circle r="4"/>
81+ <animateMotion dur="8s" repeatCount="indefinite" calcMode="spline" keyPoints="0;0;1;1" keyTimes="0;.04;.17;1" keySplines="0 0 1 1;.5 0 .3 1;0 0 1 1"><mpath href="#hub-in1"/></animateMotion>
82+ <animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;1;0;0" keyTimes="0;.04;.06;.16;.17;1"/>
83+ </g>
84+ <g class="hub-dot" opacity="0">
85+ <circle r="9"/><circle r="4"/>
86+ <animateMotion dur="8s" repeatCount="indefinite" calcMode="spline" keyPoints="0;0;1;1" keyTimes="0;.10;.23;1" keySplines="0 0 1 1;.5 0 .3 1;0 0 1 1"><mpath href="#hub-in2"/></animateMotion>
87+ <animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;1;0;0" keyTimes="0;.10;.12;.22;.23;1"/>
88+ </g>
89+ <g class="hub-dot" opacity="0">
90+ <circle r="9"/><circle r="4"/>
91+ <animateMotion dur="8s" repeatCount="indefinite" calcMode="spline" keyPoints="0;0;1;1" keyTimes="0;.16;.29;1" keySplines="0 0 1 1;.5 0 .3 1;0 0 1 1"><mpath href="#hub-in3"/></animateMotion>
92+ <animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;1;0;0" keyTimes="0;.16;.18;.28;.29;1"/>
93+ </g>
94+ <g class="hub-dot" opacity="0">
95+ <circle r="9"/><circle r="4"/>
96+ <animateMotion dur="8s" repeatCount="indefinite" calcMode="spline" keyPoints="0;0;1;1" keyTimes="0;.40;.53;1" keySplines="0 0 1 1;.5 0 .3 1;0 0 1 1"><mpath href="#hub-out1"/></animateMotion>
97+ <animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;1;0;0" keyTimes="0;.40;.42;.52;.53;1"/>
98+ </g>
99+ <g class="hub-dot" opacity="0">
100+ <circle r="9"/><circle r="4"/>
101+ <animateMotion dur="8s" repeatCount="indefinite" calcMode="spline" keyPoints="0;0;1;1" keyTimes="0;.45;.58;1" keySplines="0 0 1 1;.5 0 .3 1;0 0 1 1"><mpath href="#hub-out2"/></animateMotion>
102+ <animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;1;0;0" keyTimes="0;.45;.47;.57;.58;1"/>
103+ </g>
104+ <g class="hub-dot" opacity="0">
105+ <circle r="9"/><circle r="4"/>
106+ <animateMotion dur="8s" repeatCount="indefinite" calcMode="spline" keyPoints="0;0;1;1" keyTimes="0;.50;.63;1" keySplines="0 0 1 1;.5 0 .3 1;0 0 1 1"><mpath href="#hub-out3"/></animateMotion>
107+ <animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;1;0;0" keyTimes="0;.50;.52;.62;.63;1"/>
108+ </g>
109+ </g>
110+
111+ <!-- sources -->
112+ <g class="hub-chip">
113+ <rect x="24" y="16" width="112" height="34" rx="17"/><text x="80" y="37.5">~/.claude</text>
114+ <rect class="fx hub-flash" x="24" y="16" width="112" height="34" rx="17" opacity="0"><animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;0;0" keyTimes="0;.02;.04;.14;1"/></rect>
115+ </g>
116+ <g class="hub-chip">
117+ <rect x="184" y="16" width="112" height="34" rx="17"/><text x="240" y="37.5">anthropic</text>
118+ <rect class="fx hub-flash" x="184" y="16" width="112" height="34" rx="17" opacity="0"><animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;0;0" keyTimes="0;.08;.10;.20;1"/></rect>
119+ </g>
120+ <g class="hub-chip">
121+ <rect x="344" y="16" width="112" height="34" rx="17"/><text x="400" y="37.5">git repo</text>
122+ <rect class="fx hub-flash" x="344" y="16" width="112" height="34" rx="17" opacity="0"><animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;0;0" keyTimes="0;.14;.16;.26;1"/></rect>
123+ </g>
124+
125+ <g class="hub-label"><rect x="209" y="89" width="62" height="22" rx="11"/><text x="240" y="104">import</text></g>
126+
127+ <!-- the catalog -->
128+ <g class="hub-cat">
129+ <rect class="hub-cat-card" x="100" y="150" width="280" height="160" rx="18"/>
130+ <rect class="hub-mark-on" x="124" y="167" width="6" height="6" rx="1"/>
131+ <rect class="hub-mark-on" x="133" y="176" width="6" height="6" rx="1"/>
132+ <rect class="hub-mark-accent" x="124" y="176" width="6" height="6" rx="1"/>
133+ <text class="hub-cat-name" x="150" y="180">catalog</text>
134+ <text class="hub-cat-path" x="362" y="180">git</text>
135+
136+ <rect class="fx hub-row-flash" x="112" y="220" width="256" height="24" rx="7" opacity="0"><animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;0;0" keyTimes="0;.17;.19;.31;1"/></rect>
137+ <rect class="fx hub-row-flash" x="112" y="194" width="256" height="24" rx="7" opacity="0"><animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;0;0" keyTimes="0;.23;.25;.37;1"/></rect>
138+ <rect class="fx hub-row-flash" x="112" y="246" width="256" height="24" rx="7" opacity="0"><animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;0;0" keyTimes="0;.29;.31;.43;1"/></rect>
139+
140+ <text class="hub-tag" x="124" y="210.5">skill</text><text class="hub-item" x="176" y="210.5">nuxt</text>
141+ <text class="hub-tag" x="124" y="236.5">skill</text><text class="hub-item" x="176" y="236.5">code-review</text>
142+ <text class="hub-tag" x="124" y="262.5">rule</text><text class="hub-item" x="176" y="262.5">typescript</text>
143+ <text class="hub-tag" x="124" y="288.5">mcp</text><text class="hub-item" x="176" y="288.5">nuxt-docs</text>
144+
145+ <rect class="fx hub-ring" x="100" y="150" width="280" height="160" rx="18" opacity="0"><animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;0;0" keyTimes="0;.35;.38;.50;1"/></rect>
146+ </g>
147+
148+ <g class="hub-label"><rect x="212" y="350" width="56" height="22" rx="11"/><text x="240" y="365">apply</text></g>
149+
150+ <!-- projects: file dots are blue (pending) until their item lands, then green (written) -->
151+ <g class="hub-proj">
152+ <rect x="16" y="412" width="128" height="72" rx="14"/>
153+ <text x="30" y="438">acme-shop</text>
154+ <circle class="hub-ok" cx="34" cy="456" r="3"/><rect class="hub-bar" x="44" y="453" width="78" height="6" rx="3"/>
155+ <circle class="hub-ok" cx="34" cy="470" r="3"/><rect class="hub-bar" x="44" y="467" width="56" height="6" rx="3"/>
156+ <g class="fx" opacity="0">
157+ <circle class="hub-pending" cx="34" cy="456" r="3.4"/><circle class="hub-pending" cx="34" cy="470" r="3.4"/>
158+ <animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="1;1;0;0;1" keyTimes="0;.53;.56;.93;1"/>
159+ </g>
160+ <rect class="fx hub-flash" x="16" y="412" width="128" height="72" rx="14" opacity="0"><animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;0;0" keyTimes="0;.53;.55;.67;1"/></rect>
161+ </g>
162+ <g class="hub-proj">
163+ <rect x="176" y="412" width="128" height="72" rx="14"/>
164+ <text x="190" y="438">billing-api</text>
165+ <circle class="hub-ok" cx="194" cy="456" r="3"/><rect class="hub-bar" x="204" y="453" width="84" height="6" rx="3"/>
166+ <circle class="hub-ok" cx="194" cy="470" r="3"/><rect class="hub-bar" x="204" y="467" width="48" height="6" rx="3"/>
167+ <g class="fx" opacity="0">
168+ <circle class="hub-pending" cx="194" cy="456" r="3.4"/><circle class="hub-pending" cx="194" cy="470" r="3.4"/>
169+ <animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="1;1;0;0;1" keyTimes="0;.58;.61;.93;1"/>
170+ </g>
171+ <rect class="fx hub-flash" x="176" y="412" width="128" height="72" rx="14" opacity="0"><animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;0;0" keyTimes="0;.58;.60;.72;1"/></rect>
172+ </g>
173+ <g class="hub-proj">
174+ <rect x="336" y="412" width="128" height="72" rx="14"/>
175+ <text x="350" y="438">blog</text>
176+ <circle class="hub-ok" cx="354" cy="456" r="3"/><rect class="hub-bar" x="364" y="453" width="62" height="6" rx="3"/>
177+ <circle class="hub-ok" cx="354" cy="470" r="3"/><rect class="hub-bar" x="364" y="467" width="80" height="6" rx="3"/>
178+ <g class="fx" opacity="0">
179+ <circle class="hub-pending" cx="354" cy="456" r="3.4"/><circle class="hub-pending" cx="354" cy="470" r="3.4"/>
180+ <animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="1;1;0;0;1" keyTimes="0;.63;.66;.93;1"/>
181+ </g>
182+ <rect class="fx hub-flash" x="336" y="412" width="128" height="72" rx="14" opacity="0"><animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;0;0" keyTimes="0;.63;.65;.77;1"/></rect>
183+ </g>
184+ </svg>
185+ </figure>
51186 </section>
52187
53188 <section class="tour" id="tour" aria-labelledby="tour-title">
@@ -37,17 +37,152 @@
37 <a href="#how">How it works</a>37 <a href="#how">How it works</a>
38 <a href="#try">Try it</a>38 <a href="#try">Try it</a>
39 </nav>39 </nav>
40- <a class="btn btn-ink btn-sm" href="https://rickub.com/hlassiege/skilly">Source code</a>40+ <a class="btn btn-ink btn-sm" href="https://rickub.com/hlassiege/skilly"><svg class="btn-icon" viewBox="0 0 64 64" aria-hidden="true"><path d="M32 8 A24 24 0 1 1 12 44"/><path d="M32 18 A14 14 0 1 0 46 32"/><circle cx="32" cy="32" r="6.5"/></svg>Source code</a>
41 </header>41 </header>
42 42
43 <main id="main">43 <main id="main">
44 <section class="hero">44 <section class="hero">
45- <h1>Stop copying skills from project to&nbsp;project.</h1>45+ <div class="hero-copy">
46- <p class="lead">One catalog for your skills, rules and MCP servers.</p>46+ <h1>Stop copying skills from project to&nbsp;project.</h1>
47- <div class="actions">47+ <p class="lead">One catalog for your skills, rules and MCP servers.</p>
48- <a class="btn btn-ink" href="#try">Try it</a>48+ <div class="actions">
49- <a class="btn btn-line" href="https://rickub.com/hlassiege/skilly">Source code</a>49+ <a class="btn btn-ink" href="#try">Try it</a>
50+ <a class="btn btn-line" href="https://rickub.com/hlassiege/skilly"><svg class="btn-icon" viewBox="0 0 64 64" aria-hidden="true"><path d="M32 8 A24 24 0 1 1 12 44"/><path d="M32 18 A14 14 0 1 0 46 32"/><circle cx="32" cy="32" r="6.5"/></svg>Source code</a>
51+ </div>
52+ <p class="perk">
53+ <svg viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7"/></svg>
54+ Free and open source
55+ </p>
50 </div>56 </div>
57+
58+ <!-- The hub: sources flow into one catalog, the catalog flows out to each project.
59+ The static drawing is the final state; everything in .fx is SMIL motion on one 8s clock
60+ (same dur everywhere, timed with keyTimes), hidden when reduced motion is requested. -->
61+ <figure class="hub">
62+ <svg viewBox="0 0 480 500" role="img" aria-label="Skills from ~/.claude, Anthropic and git repos go into one catalog, then out to each project">
63+ <defs>
64+ <path id="hub-in1" d="M80 50 C80 100 200 100 200 150"/>
65+ <path id="hub-in2" d="M240 50 L240 150"/>
66+ <path id="hub-in3" d="M400 50 C400 100 280 100 280 150"/>
67+ <path id="hub-out1" d="M200 310 C200 362 80 360 80 412"/>
68+ <path id="hub-out2" d="M240 310 L240 412"/>
69+ <path id="hub-out3" d="M280 310 C280 362 400 360 400 412"/>
70+ </defs>
71+
72+ <g class="hub-lines">
73+ <use href="#hub-in1"/><use href="#hub-in2"/><use href="#hub-in3"/>
74+ <use href="#hub-out1"/><use href="#hub-out2"/><use href="#hub-out3"/>
75+ </g>
76+
77+ <!-- travelling items, drawn under the cards so they slide in and out of them -->
78+ <g class="fx">
79+ <g class="hub-dot" opacity="0">
80+ <circle r="9"/><circle r="4"/>
81+ <animateMotion dur="8s" repeatCount="indefinite" calcMode="spline" keyPoints="0;0;1;1" keyTimes="0;.04;.17;1" keySplines="0 0 1 1;.5 0 .3 1;0 0 1 1"><mpath href="#hub-in1"/></animateMotion>
82+ <animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;1;0;0" keyTimes="0;.04;.06;.16;.17;1"/>
83+ </g>
84+ <g class="hub-dot" opacity="0">
85+ <circle r="9"/><circle r="4"/>
86+ <animateMotion dur="8s" repeatCount="indefinite" calcMode="spline" keyPoints="0;0;1;1" keyTimes="0;.10;.23;1" keySplines="0 0 1 1;.5 0 .3 1;0 0 1 1"><mpath href="#hub-in2"/></animateMotion>
87+ <animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;1;0;0" keyTimes="0;.10;.12;.22;.23;1"/>
88+ </g>
89+ <g class="hub-dot" opacity="0">
90+ <circle r="9"/><circle r="4"/>
91+ <animateMotion dur="8s" repeatCount="indefinite" calcMode="spline" keyPoints="0;0;1;1" keyTimes="0;.16;.29;1" keySplines="0 0 1 1;.5 0 .3 1;0 0 1 1"><mpath href="#hub-in3"/></animateMotion>
92+ <animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;1;0;0" keyTimes="0;.16;.18;.28;.29;1"/>
93+ </g>
94+ <g class="hub-dot" opacity="0">
95+ <circle r="9"/><circle r="4"/>
96+ <animateMotion dur="8s" repeatCount="indefinite" calcMode="spline" keyPoints="0;0;1;1" keyTimes="0;.40;.53;1" keySplines="0 0 1 1;.5 0 .3 1;0 0 1 1"><mpath href="#hub-out1"/></animateMotion>
97+ <animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;1;0;0" keyTimes="0;.40;.42;.52;.53;1"/>
98+ </g>
99+ <g class="hub-dot" opacity="0">
100+ <circle r="9"/><circle r="4"/>
101+ <animateMotion dur="8s" repeatCount="indefinite" calcMode="spline" keyPoints="0;0;1;1" keyTimes="0;.45;.58;1" keySplines="0 0 1 1;.5 0 .3 1;0 0 1 1"><mpath href="#hub-out2"/></animateMotion>
102+ <animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;1;0;0" keyTimes="0;.45;.47;.57;.58;1"/>
103+ </g>
104+ <g class="hub-dot" opacity="0">
105+ <circle r="9"/><circle r="4"/>
106+ <animateMotion dur="8s" repeatCount="indefinite" calcMode="spline" keyPoints="0;0;1;1" keyTimes="0;.50;.63;1" keySplines="0 0 1 1;.5 0 .3 1;0 0 1 1"><mpath href="#hub-out3"/></animateMotion>
107+ <animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;1;0;0" keyTimes="0;.50;.52;.62;.63;1"/>
108+ </g>
109+ </g>
110+
111+ <!-- sources -->
112+ <g class="hub-chip">
113+ <rect x="24" y="16" width="112" height="34" rx="17"/><text x="80" y="37.5">~/.claude</text>
114+ <rect class="fx hub-flash" x="24" y="16" width="112" height="34" rx="17" opacity="0"><animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;0;0" keyTimes="0;.02;.04;.14;1"/></rect>
115+ </g>
116+ <g class="hub-chip">
117+ <rect x="184" y="16" width="112" height="34" rx="17"/><text x="240" y="37.5">anthropic</text>
118+ <rect class="fx hub-flash" x="184" y="16" width="112" height="34" rx="17" opacity="0"><animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;0;0" keyTimes="0;.08;.10;.20;1"/></rect>
119+ </g>
120+ <g class="hub-chip">
121+ <rect x="344" y="16" width="112" height="34" rx="17"/><text x="400" y="37.5">git repo</text>
122+ <rect class="fx hub-flash" x="344" y="16" width="112" height="34" rx="17" opacity="0"><animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;0;0" keyTimes="0;.14;.16;.26;1"/></rect>
123+ </g>
124+
125+ <g class="hub-label"><rect x="209" y="89" width="62" height="22" rx="11"/><text x="240" y="104">import</text></g>
126+
127+ <!-- the catalog -->
128+ <g class="hub-cat">
129+ <rect class="hub-cat-card" x="100" y="150" width="280" height="160" rx="18"/>
130+ <rect class="hub-mark-on" x="124" y="167" width="6" height="6" rx="1"/>
131+ <rect class="hub-mark-on" x="133" y="176" width="6" height="6" rx="1"/>
132+ <rect class="hub-mark-accent" x="124" y="176" width="6" height="6" rx="1"/>
133+ <text class="hub-cat-name" x="150" y="180">catalog</text>
134+ <text class="hub-cat-path" x="362" y="180">git</text>
135+
136+ <rect class="fx hub-row-flash" x="112" y="220" width="256" height="24" rx="7" opacity="0"><animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;0;0" keyTimes="0;.17;.19;.31;1"/></rect>
137+ <rect class="fx hub-row-flash" x="112" y="194" width="256" height="24" rx="7" opacity="0"><animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;0;0" keyTimes="0;.23;.25;.37;1"/></rect>
138+ <rect class="fx hub-row-flash" x="112" y="246" width="256" height="24" rx="7" opacity="0"><animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;0;0" keyTimes="0;.29;.31;.43;1"/></rect>
139+
140+ <text class="hub-tag" x="124" y="210.5">skill</text><text class="hub-item" x="176" y="210.5">nuxt</text>
141+ <text class="hub-tag" x="124" y="236.5">skill</text><text class="hub-item" x="176" y="236.5">code-review</text>
142+ <text class="hub-tag" x="124" y="262.5">rule</text><text class="hub-item" x="176" y="262.5">typescript</text>
143+ <text class="hub-tag" x="124" y="288.5">mcp</text><text class="hub-item" x="176" y="288.5">nuxt-docs</text>
144+
145+ <rect class="fx hub-ring" x="100" y="150" width="280" height="160" rx="18" opacity="0"><animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;0;0" keyTimes="0;.35;.38;.50;1"/></rect>
146+ </g>
147+
148+ <g class="hub-label"><rect x="212" y="350" width="56" height="22" rx="11"/><text x="240" y="365">apply</text></g>
149+
150+ <!-- projects: file dots are blue (pending) until their item lands, then green (written) -->
151+ <g class="hub-proj">
152+ <rect x="16" y="412" width="128" height="72" rx="14"/>
153+ <text x="30" y="438">acme-shop</text>
154+ <circle class="hub-ok" cx="34" cy="456" r="3"/><rect class="hub-bar" x="44" y="453" width="78" height="6" rx="3"/>
155+ <circle class="hub-ok" cx="34" cy="470" r="3"/><rect class="hub-bar" x="44" y="467" width="56" height="6" rx="3"/>
156+ <g class="fx" opacity="0">
157+ <circle class="hub-pending" cx="34" cy="456" r="3.4"/><circle class="hub-pending" cx="34" cy="470" r="3.4"/>
158+ <animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="1;1;0;0;1" keyTimes="0;.53;.56;.93;1"/>
159+ </g>
160+ <rect class="fx hub-flash" x="16" y="412" width="128" height="72" rx="14" opacity="0"><animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;0;0" keyTimes="0;.53;.55;.67;1"/></rect>
161+ </g>
162+ <g class="hub-proj">
163+ <rect x="176" y="412" width="128" height="72" rx="14"/>
164+ <text x="190" y="438">billing-api</text>
165+ <circle class="hub-ok" cx="194" cy="456" r="3"/><rect class="hub-bar" x="204" y="453" width="84" height="6" rx="3"/>
166+ <circle class="hub-ok" cx="194" cy="470" r="3"/><rect class="hub-bar" x="204" y="467" width="48" height="6" rx="3"/>
167+ <g class="fx" opacity="0">
168+ <circle class="hub-pending" cx="194" cy="456" r="3.4"/><circle class="hub-pending" cx="194" cy="470" r="3.4"/>
169+ <animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="1;1;0;0;1" keyTimes="0;.58;.61;.93;1"/>
170+ </g>
171+ <rect class="fx hub-flash" x="176" y="412" width="128" height="72" rx="14" opacity="0"><animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;0;0" keyTimes="0;.58;.60;.72;1"/></rect>
172+ </g>
173+ <g class="hub-proj">
174+ <rect x="336" y="412" width="128" height="72" rx="14"/>
175+ <text x="350" y="438">blog</text>
176+ <circle class="hub-ok" cx="354" cy="456" r="3"/><rect class="hub-bar" x="364" y="453" width="62" height="6" rx="3"/>
177+ <circle class="hub-ok" cx="354" cy="470" r="3"/><rect class="hub-bar" x="364" y="467" width="80" height="6" rx="3"/>
178+ <g class="fx" opacity="0">
179+ <circle class="hub-pending" cx="354" cy="456" r="3.4"/><circle class="hub-pending" cx="354" cy="470" r="3.4"/>
180+ <animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="1;1;0;0;1" keyTimes="0;.63;.66;.93;1"/>
181+ </g>
182+ <rect class="fx hub-flash" x="336" y="412" width="128" height="72" rx="14" opacity="0"><animate attributeName="opacity" dur="8s" repeatCount="indefinite" values="0;0;1;0;0" keyTimes="0;.63;.65;.77;1"/></rect>
183+ </g>
184+ </svg>
185+ </figure>
51 </section>186 </section>
52 187
53 <section class="tour" id="tour" aria-labelledby="tour-title">188 <section class="tour" id="tour" aria-labelledby="tour-title">
modified site/public/styles.css +60 -2
@@ -135,6 +135,11 @@ h3 { font-size: 1.0625rem; font-weight: 600; line-height: 1.35; }
135135 border: 0;
136136 }
137137 .btn-sm { height: 34px; padding: 0 14px; font-size: 0.875rem; }
138+
139+/* The rickub portal mark (from rickub.com's mask icon), drawn in the button's text color */
140+.btn-icon { flex: none; width: 1.1em; height: 1.1em; margin-right: 0.5em; }
141+.btn-icon path { fill: none; stroke: currentColor; stroke-width: 7; stroke-linecap: round; }
142+.btn-icon circle { fill: currentColor; }
138143 .btn-ink { background: var(--ink); color: var(--onink); }
139144 .btn-ink:hover { color: var(--onink); background: color-mix(in oklch, var(--ink) 86%, var(--bg)); }
140145 .btn-line { background: var(--panel); color: var(--text); box-shadow: 0 0 0 1px var(--line); }
@@ -175,12 +180,23 @@ h3 { font-size: 1.0625rem; font-weight: 600; line-height: 1.35; }
175180 }
176181
177182 /* ------------------------------------------------------------------ hero */
178-.hero { padding-top: clamp(56px, 10vw, 120px); }
183+.hero {
184+ display: grid;
185+ grid-template-columns: minmax(0, 1fr) minmax(0, 460px);
186+ gap: clamp(32px, 5vw, 72px);
187+ align-items: center;
188+ padding-top: clamp(56px, 10vw, 120px);
189+}
190+
191+@media (max-width: 960px) {
192+ .hero { grid-template-columns: 1fr; gap: 56px; }
193+ .hub { width: min(100%, 440px); justify-self: center; }
194+}
179195
180196 .hero h1 {
181197 font-family: var(--mono);
182198 font-weight: 400;
183- font-size: clamp(2.125rem, 5.6vw, 4rem);
199+ font-size: clamp(2.125rem, 4.8vw, 4rem);
184200 line-height: 1.06;
185201 letter-spacing: -0.035em;
186202 max-width: 19ch;
@@ -197,6 +213,47 @@ h3 { font-size: 1.0625rem; font-weight: 600; line-height: 1.35; }
197213
198214 .actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 36px; }
199215
216+.perk {
217+ display: flex; align-items: center; gap: 8px;
218+ margin-top: 20px;
219+ color: var(--muted); font-size: 0.9375rem;
220+}
221+.perk svg { flex: none; fill: none; stroke: var(--info); stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
222+
223+/* The hub drawing. SVG units: CSS px below are viewBox units, so the whole drawing scales as one. */
224+.hub { margin: 0; }
225+.hub svg { display: block; width: 100%; height: auto; overflow: visible; }
226+.hub text { font-family: var(--mono); font-size: 12px; }
227+
228+.hub-lines use { fill: none; stroke: var(--faint); stroke-opacity: 0.45; stroke-width: 1.25; stroke-dasharray: 3 4; }
229+
230+.hub-dot circle:first-child { fill: var(--accent); opacity: 0.22; }
231+.hub-dot circle:last-child { fill: var(--accent); }
232+
233+.hub-chip rect:first-child,
234+.hub-proj > rect:first-child { fill: var(--panel); stroke: var(--ring); stroke-width: 1; }
235+.hub-chip text { fill: var(--muted); text-anchor: middle; }
236+.hub-flash { fill: none; stroke: var(--accent); stroke-width: 1.5; }
237+
238+.hub-label rect { fill: var(--bg); stroke: var(--line); }
239+.hub-label text { fill: var(--faint); font-size: 11px; text-anchor: middle; }
240+
241+.hub-cat-card { fill: var(--ink); }
242+.hub-cat { filter: drop-shadow(0 18px 28px rgba(28, 27, 25, 0.22)); }
243+.hub-mark-on { fill: var(--onink); }
244+.hub-mark-accent { fill: var(--accent); }
245+.hub .hub-cat-name { font-family: var(--sans); font-weight: 600; font-size: 15px; fill: var(--onink); }
246+.hub .hub-cat-path { fill: var(--onink); opacity: 0.5; font-size: 11px; text-anchor: end; }
247+.hub .hub-tag { fill: var(--onink); opacity: 0.5; font-size: 11px; }
248+.hub .hub-item { font-family: var(--sans); font-size: 13.5px; fill: var(--onink); }
249+.hub-row-flash { fill: var(--accent); fill-opacity: 0.3; }
250+.hub-ring { fill: none; stroke: var(--accent); stroke-width: 2; }
251+
252+.hub-proj text { fill: var(--text); font-size: 13px; }
253+.hub-ok { fill: var(--ok); }
254+.hub-pending { fill: var(--info); }
255+.hub-bar { fill: var(--line); }
256+
200257 /* ------------------------------------------------------------------ tour: tabs on the left, screenshot on the right */
201258 .hero + .tour { margin-top: clamp(56px, 8vw, 88px); }
202259
@@ -379,4 +436,5 @@ h3 { font-size: 1.0625rem; font-weight: 600; line-height: 1.35; }
379436 @media (prefers-reduced-motion: reduce) {
380437 html { scroll-behavior: auto; }
381438 *, *::before, *::after { transition: none !important; }
439+ .hub .fx { display: none; } /* the hub then shows its final state */
382440 }
@@ -135,6 +135,11 @@ h3 { font-size: 1.0625rem; font-weight: 600; line-height: 1.35; }
135 border: 0;135 border: 0;
136 }136 }
137 .btn-sm { height: 34px; padding: 0 14px; font-size: 0.875rem; }137 .btn-sm { height: 34px; padding: 0 14px; font-size: 0.875rem; }
138+
139+/* The rickub portal mark (from rickub.com's mask icon), drawn in the button's text color */
140+.btn-icon { flex: none; width: 1.1em; height: 1.1em; margin-right: 0.5em; }
141+.btn-icon path { fill: none; stroke: currentColor; stroke-width: 7; stroke-linecap: round; }
142+.btn-icon circle { fill: currentColor; }
138 .btn-ink { background: var(--ink); color: var(--onink); }143 .btn-ink { background: var(--ink); color: var(--onink); }
139 .btn-ink:hover { color: var(--onink); background: color-mix(in oklch, var(--ink) 86%, var(--bg)); }144 .btn-ink:hover { color: var(--onink); background: color-mix(in oklch, var(--ink) 86%, var(--bg)); }
140 .btn-line { background: var(--panel); color: var(--text); box-shadow: 0 0 0 1px var(--line); }145 .btn-line { background: var(--panel); color: var(--text); box-shadow: 0 0 0 1px var(--line); }
@@ -175,12 +180,23 @@ h3 { font-size: 1.0625rem; font-weight: 600; line-height: 1.35; }
175 }180 }
176 181
177 /* ------------------------------------------------------------------ hero */182 /* ------------------------------------------------------------------ hero */
178-.hero { padding-top: clamp(56px, 10vw, 120px); }183+.hero {
184+ display: grid;
185+ grid-template-columns: minmax(0, 1fr) minmax(0, 460px);
186+ gap: clamp(32px, 5vw, 72px);
187+ align-items: center;
188+ padding-top: clamp(56px, 10vw, 120px);
189+}
190+
191+@media (max-width: 960px) {
192+ .hero { grid-template-columns: 1fr; gap: 56px; }
193+ .hub { width: min(100%, 440px); justify-self: center; }
194+}
179 195
180 .hero h1 {196 .hero h1 {
181 font-family: var(--mono);197 font-family: var(--mono);
182 font-weight: 400;198 font-weight: 400;
183- font-size: clamp(2.125rem, 5.6vw, 4rem);199+ font-size: clamp(2.125rem, 4.8vw, 4rem);
184 line-height: 1.06;200 line-height: 1.06;
185 letter-spacing: -0.035em;201 letter-spacing: -0.035em;
186 max-width: 19ch;202 max-width: 19ch;
@@ -197,6 +213,47 @@ h3 { font-size: 1.0625rem; font-weight: 600; line-height: 1.35; }
197 213
198 .actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 36px; }214 .actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 36px; }
199 215
216+.perk {
217+ display: flex; align-items: center; gap: 8px;
218+ margin-top: 20px;
219+ color: var(--muted); font-size: 0.9375rem;
220+}
221+.perk svg { flex: none; fill: none; stroke: var(--info); stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
222+
223+/* The hub drawing. SVG units: CSS px below are viewBox units, so the whole drawing scales as one. */
224+.hub { margin: 0; }
225+.hub svg { display: block; width: 100%; height: auto; overflow: visible; }
226+.hub text { font-family: var(--mono); font-size: 12px; }
227+
228+.hub-lines use { fill: none; stroke: var(--faint); stroke-opacity: 0.45; stroke-width: 1.25; stroke-dasharray: 3 4; }
229+
230+.hub-dot circle:first-child { fill: var(--accent); opacity: 0.22; }
231+.hub-dot circle:last-child { fill: var(--accent); }
232+
233+.hub-chip rect:first-child,
234+.hub-proj > rect:first-child { fill: var(--panel); stroke: var(--ring); stroke-width: 1; }
235+.hub-chip text { fill: var(--muted); text-anchor: middle; }
236+.hub-flash { fill: none; stroke: var(--accent); stroke-width: 1.5; }
237+
238+.hub-label rect { fill: var(--bg); stroke: var(--line); }
239+.hub-label text { fill: var(--faint); font-size: 11px; text-anchor: middle; }
240+
241+.hub-cat-card { fill: var(--ink); }
242+.hub-cat { filter: drop-shadow(0 18px 28px rgba(28, 27, 25, 0.22)); }
243+.hub-mark-on { fill: var(--onink); }
244+.hub-mark-accent { fill: var(--accent); }
245+.hub .hub-cat-name { font-family: var(--sans); font-weight: 600; font-size: 15px; fill: var(--onink); }
246+.hub .hub-cat-path { fill: var(--onink); opacity: 0.5; font-size: 11px; text-anchor: end; }
247+.hub .hub-tag { fill: var(--onink); opacity: 0.5; font-size: 11px; }
248+.hub .hub-item { font-family: var(--sans); font-size: 13.5px; fill: var(--onink); }
249+.hub-row-flash { fill: var(--accent); fill-opacity: 0.3; }
250+.hub-ring { fill: none; stroke: var(--accent); stroke-width: 2; }
251+
252+.hub-proj text { fill: var(--text); font-size: 13px; }
253+.hub-ok { fill: var(--ok); }
254+.hub-pending { fill: var(--info); }
255+.hub-bar { fill: var(--line); }
256+
200 /* ------------------------------------------------------------------ tour: tabs on the left, screenshot on the right */257 /* ------------------------------------------------------------------ tour: tabs on the left, screenshot on the right */
201 .hero + .tour { margin-top: clamp(56px, 8vw, 88px); }258 .hero + .tour { margin-top: clamp(56px, 8vw, 88px); }
202 259
@@ -379,4 +436,5 @@ h3 { font-size: 1.0625rem; font-weight: 600; line-height: 1.35; }
379 @media (prefers-reduced-motion: reduce) {436 @media (prefers-reduced-motion: reduce) {
380 html { scroll-behavior: auto; }437 html { scroll-behavior: auto; }
381 *, *::before, *::after { transition: none !important; }438 *, *::before, *::after { transition: none !important; }
439+ .hub .fx { display: none; } /* the hub then shows its final state */
382 }440 }