Skip to content
SlashClone

Create brand guidelines for your product

@slashclone/brand-book

Create brand guidelines for your product: one shareable HTML brand book covering logo, colors, type, icons, share images, and voice. It follows your real design tokens in light and dark themes, and a checker confirms contrast in both themes, icon and image sizes, and banned copy such as em dashes. Writes only to brand/ and public/brand/.

SkillContentv0.1.1 (latest)Tested
Activity
New: be the first to try it
  1. 1<!doctype html>
  2. 2<html lang="en" data-theme="light">
  3. 3 <head>
  4. 4 <meta charset="utf-8" />
  5. 5 <meta name="viewport" content="width=device-width, initial-scale=1" />
  6. 6 <title>Product brand book</title>
  7. 7 <link rel="icon" href="icons/favicon.svg" />
  8. 8 <style>
  9. 9 /* Fill these from brand.json. The swatch chapter reads them back, so they cannot drift. */
  10. 10 :root {
  11. 11 --page: #ffffff;
  12. 12 --card: #f4f5f7;
  13. 13 --text: #1b1d22;
  14. 14 --muted: #5b6070;
  15. 15 --accent: #2d5bd3;
  16. 16 --mark: #2d5bd3;
  17. 17 --line: rgba(0, 0, 0, 0.12);
  18. 18 --font-display: system-ui, sans-serif;
  19. 19 --font-body: system-ui, sans-serif;
  20. 20 --font-mono: ui-monospace, monospace;
  21. 21 }
  22. 22 :root[data-theme="dark"] {
  23. 23 --page: #0f1115;
  24. 24 --card: #181b21;
  25. 25 --text: #eceef2;
  26. 26 --muted: #a3a8b4;
  27. 27 --accent: #7ea2f5;
  28. 28 --mark: #4c78e6;
  29. 29 --line: rgba(255, 255, 255, 0.14);
  30. 30 }
  31. 31 * {
  32. 32 box-sizing: border-box;
  33. 33 }
  34. 34 body {
  35. 35 margin: 0;
  36. 36 background: var(--page);
  37. 37 color: var(--text);
  38. 38 font: 16px/1.6 var(--font-body);
  39. 39 }
  40. 40 nav {
  41. 41 position: sticky;
  42. 42 top: 0;
  43. 43 display: flex;
  44. 44 gap: 12px;
  45. 45 flex-wrap: wrap;
  46. 46 padding: 10px 16px;
  47. 47 background: var(--page);
  48. 48 border-bottom: 1px solid var(--line);
  49. 49 font-size: 14px;
  50. 50 z-index: 2;
  51. 51 }
  52. 52 nav a {
  53. 53 color: var(--muted);
  54. 54 text-decoration: none;
  55. 55 }
  56. 56 nav button {
  57. 57 margin-left: auto;
  58. 58 }
  59. 59 main {
  60. 60 max-width: 1040px;
  61. 61 margin: 0 auto;
  62. 62 padding: 0 16px 96px;
  63. 63 }
  64. 64 section {
  65. 65 padding: 56px 0;
  66. 66 border-bottom: 1px solid var(--line);
  67. 67 }
  68. 68 h1,
  69. 69 h2 {
  70. 70 font-family: var(--font-display);
  71. 71 line-height: 1.15;
  72. 72 }
  73. 73 h2 small {
  74. 74 display: block;
  75. 75 font: 13px var(--font-mono);
  76. 76 color: var(--muted);
  77. 77 }
  78. 78 .grid {
  79. 79 display: grid;
  80. 80 gap: 16px;
  81. 81 grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  82. 82 }
  83. 83 .card {
  84. 84 background: var(--card);
  85. 85 border: 1px solid var(--line);
  86. 86 border-radius: 12px;
  87. 87 padding: 16px;
  88. 88 }
  89. 89 .swatch {
  90. 90 height: 72px;
  91. 91 border-radius: 8px;
  92. 92 border: 1px solid var(--line);
  93. 93 }
  94. 94 .mono {
  95. 95 font-family: var(--font-mono);
  96. 96 font-size: 13px;
  97. 97 }
  98. 98 .clear {
  99. 99 display: inline-block;
  100. 100 padding: var(--clear, 24px);
  101. 101 outline: 1px dashed var(--accent);
  102. 102 }
  103. 103 .mark {
  104. 104 color: var(--mark);
  105. 105 display: block;
  106. 106 }
  107. 107 .misuse {
  108. 108 position: relative;
  109. 109 }
  110. 110 .misuse::after {
  111. 111 content: "Don't";
  112. 112 position: absolute;
  113. 113 top: 8px;
  114. 114 right: 8px;
  115. 115 font-size: 12px;
  116. 116 color: var(--muted);
  117. 117 }
  118. 118 .do-dont {
  119. 119 display: grid;
  120. 120 gap: 16px;
  121. 121 grid-template-columns: 1fr 1fr;
  122. 122 }
  123. 123 @media (max-width: 640px) {
  124. 124 .do-dont {
  125. 125 grid-template-columns: 1fr;
  126. 126 }
  127. 127 }
  128. 128 </style>
  129. 129 </head>
  130. 130 <body>
  131. 131 <nav>
  132. 132 <a href="#foundation">Foundation</a><a href="#logo">Logo</a><a href="#color">Color</a>
  133. 133 <a href="#type">Type</a><a href="#imagery">Imagery</a><a href="#share">Share</a>
  134. 134 <a href="#icons">Icons</a><a href="#voice">Voice</a><a href="#downloads">Downloads</a>
  135. 135 <a href="#sources">Sources</a>
  136. 136 <button id="theme" type="button">Switch theme</button>
  137. 137 </nav>
  138. 138 <main>
  139. 139 <header>
  140. 140 <h1>Product brand book</h1>
  141. 141 <p class="mono">Edition 1</p>
  142. 142 </header>
  143. 144 <section id="foundation">
  144. 145 <h2><small>01 Foundation</small>What we make, for whom</h2>
  145. 146 <p>
  146. 147 Mission in one sentence. The one line people should repeat. Three to five principles, each
  147. 148 with a do and a don't.
  148. 149 </p>
  149. 150 </section>
  150. 152 <section id="logo">
  151. 153 <h2><small>02 Logo</small>The mark and the wordmark</h2>
  152. 154 <!-- Replace the placeholder with the real mark, inline, using currentColor so themes recolor it. -->
  153. 155 <template id="mark-src"
  154. 156 ><svg viewBox="0 0 64 64" width="100%" height="100%" aria-hidden="true">
  155. 157 <rect x="8" y="8" width="48" height="48" rx="12" fill="currentColor" /></svg
  156. 158 ></template>
  157. 159 <h3>Sizes</h3>
  158. 160 <div class="grid" id="sizes"></div>
  159. 161 <h3>Clear space</h3>
  160. 162 <p>Keep a margin of at least one unit of the mark (named here) on every side.</p>
  161. 163 <div class="clear" style="--clear: 24px">
  162. 164 <span class="mark" data-mark style="width: 96px; height: 96px"></span>
  163. 165 </div>
  164. 166 <h3>Misuse</h3>
  165. 167 <div class="grid" id="misuse"></div>
  166. 168 </section>
  167. 170 <section id="color">
  168. 171 <h2><small>03 Color</small>Tokens, light and dark</h2>
  169. 172 <p>
  170. 173 Every value comes from the product's tokens. Each swatch shows its use and the theme it
  171. 174 belongs to.
  172. 175 </p>
  173. 176 <div class="grid" id="swatches"></div>
  174. 177 </section>
  175. 179 <section id="type">
  176. 180 <h2><small>04 Type</small>Faces, sizes, and where each goes</h2>
  177. 181 <p style="font: 700 40px var(--font-display)">Display sample</p>
  178. 182 <p>Body sample. Say what the body face is for and its sizes.</p>
  179. 183 <p class="mono">Mono sample, for code and data.</p>
  180. 184 </section>
  181. 186 <section id="imagery">
  182. 187 <h2><small>05 Imagery</small>What pictures look like</h2>
  183. 188 <div class="do-dont">
  184. 189 <div class="card">
  185. 190 <strong>Do</strong>
  186. 191 <p>Describe the subject, light, and crop.</p>
  187. 192 </div>
  188. 193 <div class="card">
  189. 194 <strong>Don't</strong>
  190. 195 <p>Describe what never appears.</p>
  191. 196 </div>
  192. 197 </div>
  193. 198 </section>
  194. 200 <section id="share">
  195. 201 <h2><small>06 Share images</small>Link previews and social sizes</h2>
  196. 202 <div class="grid" id="share-grid"></div>
  197. 203 </section>
  198. 205 <section id="icons">
  199. 206 <h2><small>07 Icons</small>Favicon and app icons</h2>
  200. 207 <p>The favicon is a flat, simplified mark: detail turns to noise at 16 pixels.</p>
  201. 208 <div class="grid" id="icon-grid"></div>
  202. 209 </section>
  203. 211 <section id="voice">
  204. 212 <h2><small>08 Voice</small>How we write</h2>
  205. 213 <div class="do-dont">
  206. 214 <div class="card">
  207. 215 <strong>Do</strong>
  208. 216 <p>Plain, short sentences.</p>
  209. 217 </div>
  210. 218 <div class="card">
  211. 219 <strong>Don't</strong>
  212. 220 <p>No em dashes. Use a period, a comma, or a colon.</p>
  213. 221 </div>
  214. 222 </div>
  215. 223 </section>
  216. 225 <section id="downloads">
  217. 226 <h2><small>09 Downloads</small>Everything, in one place</h2>
  218. 227 <ul id="download-list"></ul>
  219. 228 </section>
  220. 230 <section id="sources">
  221. 231 <h2><small>10 Sources and changes</small>Where each part comes from</h2>
  222. 232 <p>
  223. 233 Code paths and scripts that generate each file go here, not in captions. Then a short log
  224. 234 of each edition.
  225. 235 </p>
  226. 236 </section>
  227. 237 </main>
  228. 238 <script>
  229. 239 // Fill from brand.json: token names, uses, and the files under brand/.
  230. 240 const TOKENS = ["page", "card", "text", "muted", "accent", "mark"];
  231. 241 const SIZES = [16, 32, 64, 128];
  232. 242 const SHARE = [["share/link-preview.png", "Link preview, 1200x630"]];
  233. 243 const ICONS = [
  234. 244 ["icons/favicon.svg", "Favicon, SVG"],
  235. 245 ["icons/icon-192.png", "App icon 192"],
  236. 246 ["icons/icon-512.png", "App icon 512"],
  237. 247 ["icons/icon-maskable-512.png", "Maskable 512"],
  238. 248 ["icons/apple-touch-icon.png", "Touch icon 180"],
  239. 249 ];
  240. 250 const MISUSE = [
  241. 251 ["scaleX(1.6)", "Do not stretch"],
  242. 252 ["rotate(-20deg)", "Do not rotate"],
  243. 253 ["none", "Do not recolor", "hue-rotate(140deg)"],
  244. 254 ["none", "No shadows or effects", "drop-shadow(4px 4px 4px #000)"],
  245. 255 ];
  246. 257 const root = document.documentElement;
  247. 258 const saved = (() => {
  248. 259 try {
  249. 260 return localStorage.getItem("theme");
  250. 261 } catch {
  251. 262 return null;
  252. 263 }
  253. 264 })();
  254. 265 root.dataset.theme =
  255. 266 saved || (matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
  256. 267 document.getElementById("theme").onclick = () => {
  257. 268 root.dataset.theme = root.dataset.theme === "dark" ? "light" : "dark";
  258. 269 try {
  259. 270 localStorage.setItem("theme", root.dataset.theme);
  260. 271 } catch {}
  261. 272 paint();
  262. 273 };
  263. 275 const markHtml = document.getElementById("mark-src").innerHTML;
  264. 276 const el = (tag, attrs, html) =>
  265. 277 Object.assign(document.createElement(tag), attrs, html ? { innerHTML: html } : {});
  266. 278 document.querySelectorAll("[data-mark]").forEach((n) => (n.innerHTML = markHtml));
  267. 279 for (const px of SIZES) {
  268. 280 const c = el("div", { className: "card" });
  269. 281 c.append(
  270. 282 el("span", { className: "mark", style: `width:${px}px;height:${px}px` }, markHtml),
  271. 283 el("p", { className: "mono" }, `${px}px`),
  272. 284 );
  273. 285 document.getElementById("sizes").append(c);
  274. 286 }
  275. 287 for (const [transform, label, filter] of MISUSE) {
  276. 288 const c = el("div", { className: "card misuse" });
  277. 289 c.append(
  278. 290 el(
  279. 291 "span",
  280. 292 {
  281. 293 className: "mark",
  282. 294 style: `width:72px;height:72px;transform:${transform};filter:${filter || "none"}`,
  283. 295 },
  284. 296 markHtml,
  285. 297 ),
  286. 298 el("p", {}, label),
  287. 299 );
  288. 300 document.getElementById("misuse").append(c);
  289. 301 }
  290. 302 const figure =
  291. 303 (id) =>
  292. 304 ([src, label]) => {
  293. 305 const c = el("div", { className: "card" });
  294. 306 c.append(
  295. 307 el("img", { src, alt: label, style: "width:100%" }),
  296. 308 el("p", { className: "mono" }, label),
  297. 309 );
  298. 310 document.getElementById(id).append(c);
  299. 311 };
  300. 312 SHARE.forEach(figure("share-grid"));
  301. 313 ICONS.forEach(figure("icon-grid"));
  302. 314 for (const [src, label] of [...SHARE, ...ICONS]) {
  303. 315 const li = el("li");
  304. 316 li.append(el("a", { href: src, download: "" }, label));
  305. 317 document.getElementById("download-list").append(li);
  306. 318 }
  307. 320 function paint() {
  308. 321 const box = document.getElementById("swatches");
  309. 322 box.innerHTML = "";
  310. 323 const css = getComputedStyle(root);
  311. 324 for (const name of TOKENS) {
  312. 325 const value = css.getPropertyValue(`--${name}`).trim();
  313. 326 const c = el("div", { className: "card" });
  314. 327 c.append(
  315. 328 el("div", { className: "swatch", style: `background:${value}` }),
  316. 329 el("p", { className: "mono" }, `${name} ${value} (${root.dataset.theme})`),
  317. 330 );
  318. 331 box.append(c);
  319. 332 }
  320. 333 }
  321. 334 paint();
  322. 335 </script>
  323. 336 </body>
  324. 337</html>

Cookies that keep you signed in and remember these choices are always on. Everything else is off until you turn it on.