Extract authenticated coulomb.social design language via designlang

Session probe lands on /vw_pages (Research). Use main designlang extract
with --cookie-file — pack ignores auth. 39 artifacts under
docs/design-extract; tolerate designlang late summary crash when cores exist.
This commit is contained in:
tegwick 2026-08-09 01:31:00 +02:00
parent 319dd00465
commit 6fe263444a
71 changed files with 4939 additions and 797 deletions

View file

@ -113,11 +113,25 @@ Until a catalog id exists, treat this as:
## designlang auth flags (reference)
**Important:** use the **main** `designlang <url>` command, not `designlang pack`.
The `pack` subcommand ignores `--cookie-file` and crawls anonymously.
```bash
# Prefer the wrapper (probes session, applies cookies, correct out dir):
./scripts/run-design-extract.sh
# Or manually:
npx designlang https://coulomb.social \
--cookie-file ~/.config/coulomb-social/auth/storage-state.json \
-o docs/design-extract \
--depth 5
-n coulomb-social \
--wait 5000 \
--depth 2 \
--interactions
```
Bubble reuses the same `coulomb_*` cookie **names** for guests and members.
A real member session is verified by landing on an app route (e.g. `/vw_pages`)
after load, not by cookie count.
Chrome extension path (optional): log in in desktop Chrome, use designlangs extension for a one-click handoff if you prefer not to use Playwright capture.

View file

@ -1,20 +0,0 @@
Design System Pack — Provenance
================================
Source: https://coulomb.social
Captured: 2026-08-08
Tool: designlang (https://designlang.app, MIT)
The token values, type scale, spacing system, and component anatomy in
this pack were inferred from the publicly-accessible computed styles of
the source URL via a headless browser. No source files, proprietary
assets, or copyrighted media were accessed or included.
You are free to use these values as a starting point, reference, or
inspiration. The packaging itself (this README, the bundle layout, the
emitter output formats) is released under MIT by the designlang project.
Trademarks, logos, brand names, and other identifiable assets of the
source remain the property of their respective owners and are not
licensed by this pack. Do not pass off this pack as the original site's
official design system without permission.

View file

@ -3,14 +3,24 @@
| Field | Value |
|-------|--------|
| Source | https://coulomb.social |
| Tool | designlang pack v12.21.0 |
| Captured | 2026-08-09 (local) |
| Auth | Cookie file present, but session matches **anonymous Bubble** defaults (3× `coulomb_*` cookies; only `algoliasearch-client-js` localStorage). Treat as **public shell** baseline, not logged-in product UI. |
| Grade | B (86/100) — thin signal (6 palette colours; voice stats 0 buttons / 0 headings) |
| Location | `docs/design-extract/` |
| Tool | designlang main extract (not `pack`) |
| Captured | 2026-08-09 |
| Auth | Playwright storageState via `--cookie-file` |
| Session probe | https://coulomb.social/vw_pages (Research \| Coulomb) |
| Pages | 7 analyzed · 3445 elements |
| Primary | `#d08728` |
| designlang exit | 1 (late summary crash after writing core files) |
## Next
## Important
1. Re-run `./scripts/capture-auth-state.sh` after a full member login (wait for app UI).
2. Script now refuses to overwrite `storage-state.json` with anonymous sessions (exit 2).
3. Re-run `./scripts/run-design-extract.sh --wait 5000` (and optionally a multi-page crawl via plain `designlang` with `--depth`) for authenticated surfaces.
`designlang pack` **does not apply cookies**. Always use
`./scripts/run-design-extract.sh` (main extract command).
## Key artifacts
- `coulomb-social-design-language.md` — LLM-oriented full description
- `coulomb-social-DESIGN.md` — agent-native DESIGN.md
- `coulomb-social-design-tokens.json` — DTCG tokens
- `coulomb-social-variables.css` / `coulomb-social-tailwind.config.js`
- `coulomb-social-preview.html` — visual preview
- `coulomb-social-voice.json` — UI chrome (Material icon buttons on Research view)

View file

@ -1,63 +0,0 @@
# coulomb.social — design system pack
> Built from `https://coulomb.social` on 2026-08-08 by [designlang](https://designlang.app) v12.21.0.
A single, polished bundle of every artifact designlang emits for coulomb.social: tokens, components, a runnable Storybook, a minimal starter, and paste-ready prompts for v0 / Lovable / Cursor / Claude Artifacts.
## At a glance
- **Grade:** B (86/100)
- **Stack:** unknown · component library: unknown
- **Type families:** Times New Roman, Helvetica, Inter
- **Palette:** 6 colors
- **Spacing base:** 2
## What's in this pack
```
coulomb-social-design-system/
├── README.md ← you are here
├── LICENSE.txt
├── tokens/ ← DTCG + Tailwind + CSS vars + Figma vars + motion + theme.js
├── components/ ← typed React stubs (anatomy.tsx)
├── storybook/ ← runnable Storybook project
├── starter/ ← minimal starter app
├── prompts/ ← v0 · Lovable · Cursor · Claude Artifacts
└── extras/ ← voice fingerprint + recipe cards
```
## Install the tokens
### Tailwind
```js
// tailwind.config.js
import config from './tokens/tailwind.config.js';
export default config;
```
### CSS variables
```html
<link rel="stylesheet" href="tokens/variables.css">
```
### Figma
In Figma → Variables panel → import `tokens/figma-variables.json`.
### Storybook
```bash
cd storybook && npm install && npm run storybook
```
## Provenance
This pack was extracted from a publicly-accessible URL and represents the *observable design language* of that site at the time of capture. Token values are inferred from computed styles — no source files were accessed. See `LICENSE.txt` for usage guidance.
Re-pack at any time:
```bash
npx designlang pack coulomb.social
```

View file

@ -1,4 +0,0 @@
// Auto-generated by designlang — component anatomy v2.
// Scaffolds. Wire into your token system; not a runtime library.
import * as React from 'react';

View file

@ -0,0 +1,115 @@
# You are building UI in the coulomb.social design system.
Source: https://coulomb.social
Extracted by designlang on 2026-08-08.
## Brand at a glance
- title Research | Coulomb
- page intent landing
- material flat
- design grade B
## Colour
- primary #d08728
- neutrals #000000 · #efefef · #616161 · #373737 · #171717 · #ffffff
## Typography
- families Helvetica · Arial · Times New Roman · Inter
- weights 400 · 500 · 600 · 700
- base size 16px
## Spacing
- scale 1px · 24px · 32px · 40px · 60px · 80px · 96px · 320px
## Radii
- scale 4px · 8px · 12px · 15px · 20px
## Motion
- durations 250ms
## Voice
- tone neutral
- pronoun third-person
- headings unknown
- CTA verbs content · favorite · format · filter · add · arrow
## Component anatomy
- button variants: [object Object] · slots: true · true · false
## Accessibility
- WCAG score 100% · failing pairs: 0
## Build rules
1. Use the colours above. **Never invent a new hex.** If you need a
shade between two existing colours, derive it via HSL adjustment
from the closest extracted colour and call out the derivation.
2. Use the extracted typography families. If you need a missing weight,
pick the nearest available weight from the list and note it.
3. Snap spacing values to the scale above. No off-scale paddings or
margins.
4. Snap border radii to the scale above.
5. Match the voice: same tone, same pronoun stance, same heading
style. Reuse the listed CTA verbs.
6. Aim for WCAG AA contrast minimum. When the brand colours fail,
prefer the foreground colour on the background colour rather than
mid-tone neutrals.
7. Reuse component anatomy when it exists — do not invent novel
structures for things the site already has.
## Available context files
designlang wrote these alongside this prompt. Reach for them when
you need ground truth:
- `<host>-design-tokens.json` — DTCG primitive · semantic · composite tokens
- `<host>-tailwind.config.js` — Tailwind v3 config
- `<host>-tailwind-v4.css` — Tailwind v4 `@theme` block
- `<host>-tokens.d.ts` — TypeScript literal-union types
- `<host>-variables.css` — bare CSS custom properties
- `<host>-reset.css` — brand-aware base styles
- `<host>-gradients.css``.grad-N` utility classes
- `<host>-anatomy.tsx` — typed React component scaffolds
- `<host>-shadcn-theme.css` — shadcn/ui theme
- `<host>-theme.js` — React / Vue / Svelte theme object
- `<host>-mcp.json` — MCP server payload (load via stdio)
- `<host>.brand.pdf` — print-ready 13-chapter brand book
When you reference the system in code, prefer importing from these
files over hard-coding values.
## Output expectations
When asked to "build a pricing page" or "make a card" or any UI:
- Produce a single self-contained component file in the appropriate
framework (React / Vue / Svelte — match what the user is using).
- Use Tailwind utility classes wired to the v4 `@theme` if Tailwind
is available; otherwise use the CSS custom properties from
`variables.css`.
- Write the headline copy using the brand voice; do not invent
generic Lorem.
- Annotate any choice where you had to bend the system, with a
one-line `// note:` comment explaining what and why.
## One-line install
```bash
npx designlang coulomb.social
```
Run this against any other URL to extract its system in the same
shape as the one above.
---
Generated by designlang. Re-extract by running `npx designlang coulomb.social`.

View file

@ -0,0 +1,109 @@
---
site: "Research | Coulomb"
url: "https://coulomb.social"
generated_at: "2026-08-08T23:30:22.030Z"
generator: "designlang@12.21.0"
intent: landing
material: flat
tokens:
colors:
primary: "#d08728"
background: "#ffffff"
foreground: "#000000"
typography:
sans: Helvetica
spacing:
base: 4
scale: "[1, 24, 32, 40, 60, 80, 96, 320]"
radii:
sm: 4
md: 8
lg: 15
xl: 20
shadows:
sm: "rgb(170, 170, 170) 2px 2px 4px 0px"
md: "rgba(23, 23, 23, 0.1) 2px 2px 8px 2px"
---
# Overview
A **landing** page (heuristic confidence 0.45), dressed in **flat** material.
> "Research | Coulomb"
The author writes in a **neutral** voice; headings tend to be **unknown** case and **tight**.
Reading order detected on the source: `—`.
Source: <https://coulomb.social>.
# Colors
| role | hex | usage |
|---|---|---|
| primary | `#d08728` | 8 |
| background | `#ffffff` | — |
| foreground | `#000000` | — |
**Neutrals:** `#000000` · `#efefef` · `#616161` · `#373737` · `#171717`
**Total unique colors detected:** 8.
# Typography
**Families**
- `Helvetica` · 1739 uses
- `Arial` · 761 uses
- `Times New Roman` · 450 uses
- `Inter` · 397 uses
# Layout
**Spacing base:** `4px` increments.
**Scale:** `1px` · `24px` · `32px` · `40px` · `60px` · `80px` · `96px` · `320px`
**Layout primitives:** 123 grid containers · 1256 flex containers.
# Elevation and Depth
**Shadow scale**
- `sm``rgb(170, 170, 170) 2px 2px 4px 0px`
- `md``rgba(23, 23, 23, 0.1) 2px 2px 8px 2px`
**Z-index layers:** 35
# Shapes
**Radius scale**
- `sm``4px`
- `md``8px`
- `lg``12px`
- `lg``15px`
- `xl``20px`
# Components
**Detected patterns:** `buttons` · `cards` · `inputs` · `links` · `modals`
**Anatomy**
| kind | variants | sizes | instances |
|---|---|---|---|
| button | — | — | 56 |
# Do's and Don'ts
**Do's**
- Use `content`, `favorite`, `format` as the primary verbs in CTAs — these dominate the source.
- Write headings in **unknown** case, **tight** length.
- Address the reader with the pronoun posture **third-person**.
- Stay inside the **flat** material — match shadow and radius habits.
**Don'ts**
- Don't 4 font families — consider limiting to 2 (heading + body).
- Don't 140 !important rules — prefer specificity over overrides.
- Don't 81% of css is unused — consider purging.
- Don't 6545 duplicate css declarations.
---
_Generated by [designlang](https://github.com/Manavarya09/design-extract) v12.21.0 from <https://coulomb.social>._
_Compatible with the DESIGN.md convention pioneered by [design-extractor.com](https://www.design-extractor.com) — extended with intent, material, voice, anatomy, and library detection._

View file

@ -0,0 +1,15 @@
// Auto-generated by designlang — component anatomy v2.
// Scaffolds. Wire into your token system; not a runtime library.
import * as React from 'react';
export interface ButtonProps {
variant?: 'default';
size?: 'md';
leadingIcon?: React.ReactNode;
children?: React.ReactNode;
}
export function Button({ variant = 'default', size = 'md', ...rest }: ButtonProps) {
return React.createElement('button', { 'data-variant': variant, 'data-size': size, ...rest });
}

View file

@ -0,0 +1,578 @@
# Design Language: Research | Coulomb
> Extracted from `https://coulomb.social` on August 9, 2026
> 3445 elements analyzed across 7 pages
This document describes the complete design language of the website. It is structured for AI/LLM consumption — use it to faithfully recreate the visual design in any framework.
## Color Palette
### Primary Colors
| Role | Hex | RGB | HSL | Usage Count |
|------|-----|-----|-----|-------------|
| Primary | `#d08728` | rgb(208, 135, 40) | hsl(34, 68%, 49%) | 8 |
### Neutral Colors
| Hex | HSL | Usage Count |
|-----|-----|-------------|
| `#000000` | hsl(0, 0%, 0%) | 5304 |
| `#efefef` | hsl(0, 0%, 94%) | 610 |
| `#616161` | hsl(0, 0%, 38%) | 556 |
| `#373737` | hsl(0, 0%, 22%) | 462 |
| `#171717` | hsl(0, 0%, 9%) | 401 |
| `#ffffff` | hsl(0, 0%, 100%) | 242 |
| `#e5e5e5` | hsl(0, 0%, 90%) | 217 |
### Background Colors
Used on large-area elements: `#ffffff`, `#e5e5e5`, `#171717`, `#f5f5f5`
### Text Colors
Text color palette: `#000000`, `#171717`, `#373737`, `#616161`, `#ffffff`
### Full Color Inventory
| Hex | Contexts | Count |
|-----|----------|-------|
| `#000000` | text, border, background | 5304 |
| `#efefef` | background | 610 |
| `#616161` | text, border | 556 |
| `#373737` | text, border | 462 |
| `#171717` | text, border, background | 401 |
| `#ffffff` | background, border, text | 242 |
| `#e5e5e5` | border, background | 217 |
| `#d08728` | background | 8 |
## Typography
### Font Families
- **Helvetica** — used for body (1739 elements)
- **Arial** — used for body (761 elements)
- **Times New Roman** — used for body (450 elements)
- **Inter** — used for body (397 elements)
### Type Scale
| Size (px) | Size (rem) | Weight | Line Height | Letter Spacing | Used On |
|-----------|------------|--------|-------------|----------------|---------|
| 50px | 3.125rem | 400 | 50px | normal | text |
| 42px | 2.625rem | 700 | normal | normal | input |
| 24px | 1.5rem | 600 | 36px | normal | a |
| 18px | 1.125rem | 600 | 18px | normal | div |
| 16px | 1rem | 400 | normal | normal | html, head, meta, title |
| 14px | 0.875rem | 500 | 19.6px | normal | div, a |
| 13.3333px | 0.8333rem | 400 | normal | normal | button, svg, use |
### Font Weights in Use
`400` (3048x), `500` (287x), `600` (102x), `700` (8x)
## Spacing
**Base unit:** 4px
| Token | Value | Rem |
|-------|-------|-----|
| spacing-1 | 1px | 0.0625rem |
| spacing-24 | 24px | 1.5rem |
| spacing-32 | 32px | 2rem |
| spacing-40 | 40px | 2.5rem |
| spacing-60 | 60px | 3.75rem |
| spacing-80 | 80px | 5rem |
| spacing-96 | 96px | 6rem |
| spacing-320 | 320px | 20rem |
## Border Radii
| Label | Value | Count |
|-------|-------|-------|
| sm | 4px | 119 |
| md | 8px | 122 |
| lg | 12px | 110 |
| lg | 15px | 6 |
| xl | 20px | 12 |
## Box Shadows
**sm** — blur: 4px
```css
box-shadow: rgb(170, 170, 170) 2px 2px 4px 0px;
```
**md** — blur: 8px
```css
box-shadow: rgba(23, 23, 23, 0.1) 2px 2px 8px 2px;
```
## CSS Custom Properties
### Colors
```css
--color_primary_default: rgba(2, 5, 211, 1);
--color_primary_default_rgb: 2, 5, 211;
--color_primary_contrast_default: rgba(255, 255, 255, 1);
--color_primary_contrast_default_rgb: 255, 255, 255;
--color_text_default: rgba(9, 23, 71, 1);
--color_text_default_rgb: 9, 23, 71;
--color_surface_default: rgba(255, 255, 255, 1);
--color_surface_default_rgb: 255, 255, 255;
--color_background_default: rgba(255, 255, 255, 0);
--color_background_default_rgb: 255, 255, 255;
--color_destructive_default: rgba(255, 0, 0, 1);
--color_destructive_default_rgb: 255, 0, 0;
--color_success_default: rgba(23, 219, 78, 1);
--color_success_default_rgb: 23, 219, 78;
--color_alert_default: rgba(250, 181, 21, 1);
--color_alert_default_rgb: 250, 181, 21;
--color_danger_default_rgb: rgba(176, 32, 12, 1);
--color_bTRUr_default_rgb: 208,135,40;
--color_bTOCs_default: rgba(55,55,55,1);
--color_bTHZK_default_rgb: 229,229,229;
--color_bTOCs_default_rgb: 55,55,55;
--color_bTINZ_default_rgb: 23,23,23;
--color_bTRUs_default_rgb: 227,230,235;
--color_bTINZ_default: rgba(23,23,23,0.36);
--color_bTRUr_default: rgba(208,135,40,0.1);
--color_bTHZK_default: rgba(229,229,229,1);
--color_bTHfJ_default_rgb: 97,97,97;
--color_bTMap_default: rgba(113,2,139,1);
--color_bTHfJ_default: rgba(97,97,97,1);
--color_bTMap_default_rgb: 113,2,139;
--color_bTRUs_default: rgba(227,230,235,1);
```
### Typography
```css
--font_default: 'Lato';
--font_bTRUx_default: "Inter";
--font_bTRUt_default: "Inter";
```
### Semantic
```css
success: [object Object];
warning: [object Object];
error: [object Object];
info: [object Object];
```
## Transitions & Animations
**Durations:** `0.25s`
### Common Transitions
```css
transition: all;
transition: background 0.25s;
```
### Keyframe Animations
**highlight-in**
```css
@keyframes highlight-in {
0% { background-color: rgb(200, 0, 0); }
}
```
**fa-spin**
```css
@keyframes fa-spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(359deg); }
}
```
**opacity-70-25-0-13**
```css
@keyframes opacity-70-25-0-13 {
0% { opacity: 0.25; }
0.01% { opacity: 0.25; }
0.02% { opacity: 1; }
70.01% { opacity: 0.25; }
100% { opacity: 0.25; }
}
```
**opacity-70-25-1-13**
```css
@keyframes opacity-70-25-1-13 {
0% { opacity: 0.25; }
7.70231% { opacity: 0.25; }
7.71231% { opacity: 1; }
77.7023% { opacity: 0.25; }
100% { opacity: 0.25; }
}
```
**opacity-70-25-2-13**
```css
@keyframes opacity-70-25-2-13 {
0% { opacity: 0.25; }
15.3946% { opacity: 0.25; }
15.4046% { opacity: 1; }
85.3946% { opacity: 0.25; }
100% { opacity: 0.25; }
}
```
**opacity-70-25-3-13**
```css
@keyframes opacity-70-25-3-13 {
0% { opacity: 0.25; }
23.0869% { opacity: 0.25; }
23.0969% { opacity: 1; }
93.0869% { opacity: 0.25; }
100% { opacity: 0.25; }
}
```
**opacity-70-25-4-13**
```css
@keyframes opacity-70-25-4-13 {
0% { opacity: 0.258349; }
30.7792% { opacity: 0.25; }
30.7892% { opacity: 1; }
0.779231% { opacity: 0.25; }
100% { opacity: 0.258349; }
}
```
**opacity-70-25-5-13**
```css
@keyframes opacity-70-25-5-13 {
0% { opacity: 0.340766; }
38.4715% { opacity: 0.25; }
38.4815% { opacity: 1; }
8.47154% { opacity: 0.25; }
100% { opacity: 0.340766; }
}
```
**opacity-70-25-6-13**
```css
@keyframes opacity-70-25-6-13 {
0% { opacity: 0.423184; }
46.1638% { opacity: 0.25; }
46.1738% { opacity: 1; }
16.1638% { opacity: 0.25; }
100% { opacity: 0.423184; }
}
```
**opacity-70-25-7-13**
```css
@keyframes opacity-70-25-7-13 {
0% { opacity: 0.505602; }
53.8562% { opacity: 0.25; }
53.8662% { opacity: 1; }
23.8562% { opacity: 0.25; }
100% { opacity: 0.505602; }
}
```
## Component Patterns
Detected UI component patterns and their most common styles:
### Buttons (643 instances)
```css
.button {
background-color: rgb(239, 239, 239);
color: rgb(0, 0, 0);
font-size: 13.3333px;
font-weight: 400;
padding-top: 1px;
padding-right: 6px;
border-radius: 0px;
}
```
### Cards (36 instances)
```css
.card {
background-color: rgb(255, 255, 255);
border-radius: 4px;
box-shadow: rgb(170, 170, 170) 2px 2px 4px 0px;
padding-top: 4px;
padding-right: 4px;
}
```
### Inputs (16 instances)
```css
.input {
color: rgb(23, 23, 23);
border-color: rgb(255, 255, 255);
border-radius: 8px;
font-size: 16px;
padding-top: 2px;
padding-right: 2px;
}
```
### Links (130 instances)
```css
.link {
color: rgb(23, 23, 23);
font-size: 16px;
font-weight: 500;
}
```
### Modals (78 instances)
```css
.modal {
background-color: rgb(255, 255, 255);
border-radius: 12px;
padding-top: 24px;
padding-right: 0px;
max-width: 280px;
}
```
## Component Clusters
Reusable component instances grouped by DOM structure and style similarity:
### Button — 55 instances, 1 variant
**Variant 1** (55 instances)
```css
background: rgba(0, 0, 0, 0);
color: rgb(55, 55, 55);
padding: 0px 0px 0px 0px;
border-radius: 4px;
border: 0px none rgb(55, 55, 55);
font-size: 13.3333px;
font-weight: 400;
```
### Button — 1 instance, 1 variant
**Variant 1** (1 instance)
```css
background: rgb(239, 239, 239);
color: rgb(0, 0, 0);
padding: 1px 6px 1px 6px;
border-radius: 0px;
border: 2px outset rgb(0, 0, 0);
font-size: 13.3333px;
font-weight: 400;
```
## Layout System
**123 grid containers** and **1256 flex containers** detected.
### Container Widths
| Max Width | Padding |
|-----------|---------|
| 1200px | 0px |
| 100% | 0px |
| 992px | 0px |
### Grid Column Patterns
| Columns | Usage Count |
|---------|-------------|
| 1-column | 122x |
| 2-column | 1x |
### Grid Templates
```css
grid-template-columns: 592px 592px;
gap: 16px;
grid-template-columns: 32px;
grid-template-columns: 32px;
grid-template-columns: 32px;
grid-template-columns: 32px;
```
### Flex Patterns
| Direction/Wrap | Count |
|----------------|-------|
| column/nowrap | 470x |
| row/nowrap | 71x |
| row/wrap | 715x |
**Gap values:** `0px 12px`, `0px 20px`, `0px 24px`, `0px 4px`, `0px 8px`, `0px normal`, `12px normal`, `16px`, `18px normal`, `24px`, `24px normal`, `4px normal`, `8px normal`
## Interaction States
### Button States
**""**
```css
/* Focus */
outline: rgb(208, 135, 40) none 3px → rgba(0, 0, 0, 0) dotted 0px;
```
### Link Hover
```css
text-decoration: none → underline;
```
## Accessibility (WCAG 2.1)
**Overall Score: 100%** — 0 passing, 0 failing color pairs
## Design System Score
**Overall: 85/100 (Grade: B)**
| Category | Score |
|----------|-------|
| Color Discipline | 100/100 |
| Typography Consistency | 50/100 |
| Spacing System | 100/100 |
| Shadow Consistency | 100/100 |
| Border Radius Consistency | 90/100 |
| Accessibility | 100/100 |
| CSS Tokenization | 100/100 |
**Strengths:** Tight, disciplined color palette, Well-defined spacing scale, Clean elevation system, Consistent border radii, Strong accessibility compliance, Good CSS variable tokenization
**Issues:**
- 4 font families — consider limiting to 2 (heading + body)
- 140 !important rules — prefer specificity over overrides
- 81% of CSS is unused — consider purging
- 6545 duplicate CSS declarations
## Z-Index Map
**35 unique z-index values** across 3 layers.
| Layer | Range | Elements |
|-------|-------|----------|
| modal | 1503,2105 | div.b.u.b.b.l.e.-.e.l.e.m.e.n.t. .C.u.s.t.o.m.E.l.e.m.e.n.t. .b.a.T.a.K.a.Q.a.X. .f.l.o.a.t.i.n.g.-.g.r.o.u.p. .b.u.b.b.l.e.-.r.-.c.o.n.t.a.i.n.e.r. .f.l.e.x. .c.o.l.u.m.n, div.b.u.b.b.l.e.-.e.l.e.m.e.n.t. .C.u.s.t.o.m.E.l.e.m.e.n.t. .b.a.T.a.K.a.Q.a.X. .f.l.o.a.t.i.n.g.-.g.r.o.u.p. .b.u.b.b.l.e.-.r.-.c.o.n.t.a.i.n.e.r. .f.l.e.x. .c.o.l.u.m.n, div.b.u.b.b.l.e.-.e.l.e.m.e.n.t. .C.u.s.t.o.m.E.l.e.m.e.n.t. .b.a.T.a.K.a.Q.a.X. .f.l.o.a.t.i.n.g.-.g.r.o.u.p. .b.u.b.b.l.e.-.r.-.c.o.n.t.a.i.n.e.r. .f.l.e.x. .c.o.l.u.m.n |
| sticky | 10,30 | div.b.u.b.b.l.e.-.e.l.e.m.e.n.t. .G.r.o.u.p. .b.a.T.a.N.a.I.d. .b.u.b.b.l.e.-.r.-.c.o.n.t.a.i.n.e.r. .f.l.e.x. .r.o.w, div.b.u.b.b.l.e.-.e.l.e.m.e.n.t. .T.e.x.t. .b.a.T.a.N.a.I.q, textarea.b.u.b.b.l.e.-.e.l.e.m.e.n.t. .M.u.l.t.i.L.i.n.e.I.n.p.u.t. .a.1.7.8.6.2.3.1.7.9.1.3.3.1.x.5.4.4.4 |
| base | 0,9 | div.b.u.b.b.l.e.-.r.-.c.o.n.t.a.i.n.e.r. .f.l.e.x. .c.o.l.u.m.n, div.b.u.b.b.l.e.-.r.-.c.o.n.t.a.i.n.e.r. .f.l.e.x. .c.o.l.u.m.n, div.b.u.b.b.l.e.-.r.-.c.o.n.t.a.i.n.e.r. .f.l.e.x. .c.o.l.u.m.n |
## SVG Icons
**7 unique SVG icons** detected. Dominant style: **filled**.
| Size Class | Count |
|------------|-------|
| md | 4 |
| lg | 2 |
| xl | 1 |
**Icon colors:** `rgb(0, 0, 0)`
## Font Files
| Family | Source | Weights | Styles |
|--------|--------|---------|--------|
| FontAwesome | self-hosted | normal | normal |
| Material Icons | self-hosted | 400 | normal |
| Material Icons Outline | self-hosted | 400 | normal |
| Inter | google-fonts | 300, 400, 500, 600, 700 | normal |
**Google Fonts URL:** `https://fonts.googleapis.com/css?family=Inter:300%7CInter:regular%7CInter:500%7CInter:600%7CInter:700`
## Image Style Patterns
| Pattern | Count | Key Styles |
|---------|-------|------------|
| thumbnail | 28 | objectFit: contain, borderRadius: 8px, shape: rounded |
| general | 1 | objectFit: cover, borderRadius: 20px, shape: pill |
**Aspect ratios:** 1:1 (28x), 2:3 (1x)
## Motion Language
**Feel:** mixed · **Scroll-linked:** yes
### Duration Tokens
| name | value | ms |
|---|---|---|
| `sm` | `250ms` | 250 |
## Component Anatomy
### button — 56 instances
**Slots:** label, icon
## Brand Voice
**Tone:** neutral · **Pronoun:** third-person · **Headings:** unknown (tight)
### Top CTA Verbs
- **content** (25)
- **favorite** (25)
- **format** (1)
- **filter** (1)
- **add** (1)
- **arrow** (1)
- **note** (1)
### Button Copy Patterns
- "content_copy" (25×)
- "favorite_border" (25×)
- "format_line_spacing" (1×)
- "filter_list" (1×)
- "add_circle_outline" (1×)
- "arrow_drop_down" (1×)
- "note_alt" (1×)
## Page Intent
**Type:** `landing` (confidence 0.45)
**Description:** A tool to brainstorm, discuss, refine implement and promote ideas.
A social network for building stuff and influencing how stuff is built.
A marketplace for challenges, methods and solutions.
A platfo
## Material Language
**Label:** `flat` (confidence 0)
| Metric | Value |
|--------|-------|
| Avg saturation | 0.101 |
| Shadow profile | soft |
| Avg shadow blur | 0px |
| Max radius | 20px |
| backdrop-filter in use | no |
| Gradients | 0 |
## Imagery Style
**Label:** `mixed` (confidence 0)
**Counts:** total 29, svg 0, icon 1, screenshot-like 0, photo-like 0
**Dominant aspect:** square-ish
**Radius profile on images:** soft
## Quick Start
To recreate this design in a new project:
1. **Install fonts:** Add `Helvetica` from Google Fonts or your font provider
2. **Import CSS variables:** Copy `variables.css` into your project
3. **Tailwind users:** Use the generated `tailwind.config.js` to extend your theme
4. **Design tokens:** Import `design-tokens.json` for tooling integration

View file

@ -4,7 +4,7 @@
"version": "7.0.0",
"spec": "https://design-tokens.github.io/community-group/format/",
"source": "https://coulomb.social",
"generatedAt": "2026-08-08T23:21:16.292Z"
"generatedAt": "2026-08-08T23:30:13.743Z"
},
"primitive": {
"color": {
@ -20,18 +20,26 @@
"$type": "color"
},
"n200": {
"$value": "#171717",
"$value": "#efefef",
"$type": "color"
},
"n300": {
"$value": "#ffffff",
"$type": "color"
},
"n400": {
"$value": "#616161",
"$type": "color"
},
"n400": {
"$value": "#373737",
"$type": "color"
},
"n500": {
"$value": "#171717",
"$type": "color"
},
"n600": {
"$value": "#ffffff",
"$type": "color"
},
"n700": {
"$value": "#e5e5e5",
"$type": "color"
}
@ -42,7 +50,15 @@
"$type": "color"
},
"bg1": {
"$value": "#616161",
"$value": "#e5e5e5",
"$type": "color"
},
"bg2": {
"$value": "#171717",
"$type": "color"
},
"bg3": {
"$value": "#f5f5f5",
"$type": "color"
}
},
@ -52,30 +68,54 @@
"$type": "color"
},
"text1": {
"$value": "#ffffff",
"$type": "color"
},
"text2": {
"$value": "#171717",
"$type": "color"
},
"text2": {
"$value": "#373737",
"$type": "color"
},
"text3": {
"$value": "#d08728",
"$value": "#616161",
"$type": "color"
},
"text4": {
"$value": "#ffffff",
"$type": "color"
}
}
},
"spacing": {
"s0": {
"$value": "2px",
"$value": "1px",
"$type": "dimension"
},
"s1": {
"$value": "32px",
"$value": "24px",
"$type": "dimension"
},
"s2": {
"$value": "68px",
"$value": "32px",
"$type": "dimension"
},
"s3": {
"$value": "40px",
"$type": "dimension"
},
"s4": {
"$value": "60px",
"$type": "dimension"
},
"s5": {
"$value": "80px",
"$type": "dimension"
},
"s6": {
"$value": "96px",
"$type": "dimension"
},
"s7": {
"$value": "320px",
"$type": "dimension"
}
},
@ -87,29 +127,45 @@
"r1": {
"$value": "8px",
"$type": "dimension"
},
"r2": {
"$value": "12px",
"$type": "dimension"
},
"r3": {
"$value": "15px",
"$type": "dimension"
},
"r4": {
"$value": "20px",
"$type": "dimension"
}
},
"shadow": {
"sh0": {
"$value": "rgb(97, 97, 97) 2px 2px 8px 0px",
"$value": "rgb(170, 170, 170) 2px 2px 4px 0px",
"$type": "shadow"
},
"sh1": {
"$value": "rgba(23, 23, 23, 0.1) 2px 2px 8px 2px",
"$type": "shadow"
}
},
"fontFamily": {
"f0": {
"$value": "Times New Roman",
"$type": "fontFamily"
},
"f1": {
"$value": "Helvetica",
"$type": "fontFamily"
},
"f1": {
"$value": "Arial",
"$type": "fontFamily"
},
"f2": {
"$value": "Inter",
"$value": "Times New Roman",
"$type": "fontFamily"
},
"f3": {
"$value": "Arial",
"$value": "Inter",
"$type": "fontFamily"
}
}
@ -138,10 +194,10 @@
"typography": {
"body": {
"$value": {
"fontFamily": "Times New Roman",
"fontSize": "48px",
"fontWeight": "700",
"lineHeight": "67.2px"
"fontFamily": "Helvetica",
"fontSize": "50px",
"fontWeight": "400",
"lineHeight": "50px"
},
"$type": "typography"
}

View file

@ -35,9 +35,9 @@
"type": "COLOR",
"values": {
"light": {
"r": 0.09019607843137255,
"g": 0.09019607843137255,
"b": 0.09019607843137255,
"r": 0.9372549019607843,
"g": 0.9372549019607843,
"b": 0.9372549019607843,
"a": 1
}
}
@ -45,18 +45,6 @@
{
"name": "color/neutral/200",
"type": "COLOR",
"values": {
"light": {
"r": 1,
"g": 1,
"b": 1,
"a": 1
}
}
},
{
"name": "color/neutral/300",
"type": "COLOR",
"values": {
"light": {
"r": 0.3803921568627451,
@ -66,9 +54,45 @@
}
}
},
{
"name": "color/neutral/300",
"type": "COLOR",
"values": {
"light": {
"r": 0.21568627450980393,
"g": 0.21568627450980393,
"b": 0.21568627450980393,
"a": 1
}
}
},
{
"name": "color/neutral/400",
"type": "COLOR",
"values": {
"light": {
"r": 0.09019607843137255,
"g": 0.09019607843137255,
"b": 0.09019607843137255,
"a": 1
}
}
},
{
"name": "color/neutral/500",
"type": "COLOR",
"values": {
"light": {
"r": 1,
"g": 1,
"b": 1,
"a": 1
}
}
},
{
"name": "color/neutral/600",
"type": "COLOR",
"values": {
"light": {
"r": 0.8980392156862745,
@ -95,9 +119,33 @@
"type": "COLOR",
"values": {
"light": {
"r": 0.3803921568627451,
"g": 0.3803921568627451,
"b": 0.3803921568627451,
"r": 0.8980392156862745,
"g": 0.8980392156862745,
"b": 0.8980392156862745,
"a": 1
}
}
},
{
"name": "color/background/2",
"type": "COLOR",
"values": {
"light": {
"r": 0.09019607843137255,
"g": 0.09019607843137255,
"b": 0.09019607843137255,
"a": 1
}
}
},
{
"name": "color/background/3",
"type": "COLOR",
"values": {
"light": {
"r": 0.9607843137254902,
"g": 0.9607843137254902,
"b": 0.9607843137254902,
"a": 1
}
}
@ -119,9 +167,9 @@
"type": "COLOR",
"values": {
"light": {
"r": 1,
"g": 1,
"b": 1,
"r": 0.09019607843137255,
"g": 0.09019607843137255,
"b": 0.09019607843137255,
"a": 1
}
}
@ -131,9 +179,9 @@
"type": "COLOR",
"values": {
"light": {
"r": 0.09019607843137255,
"g": 0.09019607843137255,
"b": 0.09019607843137255,
"r": 0.21568627450980393,
"g": 0.21568627450980393,
"b": 0.21568627450980393,
"a": 1
}
}
@ -143,9 +191,21 @@
"type": "COLOR",
"values": {
"light": {
"r": 0.8156862745098039,
"g": 0.5294117647058824,
"b": 0.1568627450980392,
"r": 0.3803921568627451,
"g": 0.3803921568627451,
"b": 0.3803921568627451,
"a": 1
}
}
},
{
"name": "color/text/4",
"type": "COLOR",
"values": {
"light": {
"r": 1,
"g": 1,
"b": 1,
"a": 1
}
}
@ -159,45 +219,59 @@
],
"variables": [
{
"name": "font/size/48",
"name": "font/size/50",
"type": "FLOAT",
"values": {
"default": 48
"default": 50
}
},
{
"name": "font/weight/48",
"name": "font/weight/50",
"type": "FLOAT",
"values": {
"default": 400
}
},
{
"name": "font/lineHeight/50",
"type": "FLOAT",
"values": {
"default": 50
}
},
{
"name": "font/size/42",
"type": "FLOAT",
"values": {
"default": 42
}
},
{
"name": "font/weight/42",
"type": "FLOAT",
"values": {
"default": 700
}
},
{
"name": "font/lineHeight/48",
"name": "font/size/24",
"type": "FLOAT",
"values": {
"default": 67.2
"default": 24
}
},
{
"name": "font/size/32",
"type": "FLOAT",
"values": {
"default": 32
}
},
{
"name": "font/weight/32",
"name": "font/weight/24",
"type": "FLOAT",
"values": {
"default": 600
}
},
{
"name": "font/lineHeight/32",
"name": "font/lineHeight/24",
"type": "FLOAT",
"values": {
"default": 44.8
"default": 36
}
},
{
@ -218,7 +292,7 @@
"name": "font/lineHeight/18",
"type": "FLOAT",
"values": {
"default": 25.2
"default": 18
}
},
{
@ -269,48 +343,6 @@
"values": {
"default": 400
}
},
{
"name": "font/size/12",
"type": "FLOAT",
"values": {
"default": 12
}
},
{
"name": "font/weight/12",
"type": "FLOAT",
"values": {
"default": 500
}
},
{
"name": "font/lineHeight/12",
"type": "FLOAT",
"values": {
"default": 16.8
}
},
{
"name": "font/size/8",
"type": "FLOAT",
"values": {
"default": 8
}
},
{
"name": "font/weight/8",
"type": "FLOAT",
"values": {
"default": 500
}
},
{
"name": "font/lineHeight/8",
"type": "FLOAT",
"values": {
"default": 11.2
}
}
]
},
@ -321,10 +353,17 @@
],
"variables": [
{
"name": "spacing/2",
"name": "spacing/1",
"type": "FLOAT",
"values": {
"default": 2
"default": 1
}
},
{
"name": "spacing/24",
"type": "FLOAT",
"values": {
"default": 24
}
},
{
@ -335,10 +374,38 @@
}
},
{
"name": "spacing/68",
"name": "spacing/40",
"type": "FLOAT",
"values": {
"default": 68
"default": 40
}
},
{
"name": "spacing/60",
"type": "FLOAT",
"values": {
"default": 60
}
},
{
"name": "spacing/80",
"type": "FLOAT",
"values": {
"default": 80
}
},
{
"name": "spacing/96",
"type": "FLOAT",
"values": {
"default": 96
}
},
{
"name": "spacing/320",
"type": "FLOAT",
"values": {
"default": 320
}
},
{
@ -354,6 +421,27 @@
"values": {
"default": 8
}
},
{
"name": "radius/lg",
"type": "FLOAT",
"values": {
"default": 12
}
},
{
"name": "radius/lg",
"type": "FLOAT",
"values": {
"default": 15
}
},
{
"name": "radius/xl",
"type": "FLOAT",
"values": {
"default": 20
}
}
]
}

View file

@ -0,0 +1,23 @@
{
"flags": [],
"forms": {
"count": 0,
"families": {}
},
"inputTypesSeen": {
"textarea": 10,
"input": 6
},
"modals": [],
"toastLibraries": [],
"loading": {
"skeleton": 0,
"spinner": 0
},
"empty": {
"count": 0
},
"error": {
"count": 0
}
}

View file

@ -0,0 +1,2 @@
/* designlang — no gradients detected on the source page. */
/* Run with --interactions to capture hover backgrounds. */

View file

@ -0,0 +1,7 @@
{
"$schema": "https://designlang.app/schemas/gradients.json",
"source": "https://coulomb.social",
"generated": "2026-08-08T23:30:22.006Z",
"count": 0,
"gradients": []
}

View file

@ -0,0 +1,199 @@
{
"library": "unknown",
"confidence": 0,
"alternates": [],
"stats": {
"count": 55,
"strokeOnly": 0,
"fillOnly": 55,
"mixed": 0,
"avgStrokeWidth": 0,
"gridDistribution": {},
"roundedCapsFraction": 0
},
"signals": [
"fillDominant"
],
"icons": [
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
},
{
"class": "",
"grid": null,
"strokeWidth": null,
"style": "fill"
}
]
}

View file

@ -0,0 +1,24 @@
{
"pageIntent": {
"type": "landing",
"confidence": 0.45,
"path": "/",
"title": "Research | Coulomb",
"description": "A tool to brainstorm, discuss, refine implement and promote ideas.\nA social network for building stuff and influencing how stuff is built.\nA marketplace for challenges, methods and solutions.\nA platfo",
"signals": [
{
"kind": "url",
"type": "landing",
"weight": 0.45,
"detail": "root-path"
}
],
"alternates": [],
"needsSmart": true
},
"sectionRoles": {
"sections": [],
"counts": {},
"readingOrder": []
}
}

View file

@ -0,0 +1,12 @@
{
"library": "unknown",
"confidence": 0,
"evidence": [],
"alternates": [],
"signals": {
"tailwindLike": 0.136,
"radixAttrCount": 0,
"classSampleSize": 467
},
"needsSmart": true
}

View file

@ -0,0 +1,275 @@
{
"colors": {
"all": [
{
"hex": "#000000",
"rgb": {
"r": 0,
"g": 0,
"b": 0,
"a": 1
},
"hsl": {
"h": 0,
"s": 0,
"l": 0
},
"count": 5304,
"contexts": [
"text",
"border",
"background"
]
},
{
"hex": "#efefef",
"rgb": {
"r": 239,
"g": 239,
"b": 239,
"a": 1
},
"hsl": {
"h": 0,
"s": 0,
"l": 94
},
"count": 610,
"contexts": [
"background"
]
},
{
"hex": "#616161",
"rgb": {
"r": 97,
"g": 97,
"b": 97,
"a": 1
},
"hsl": {
"h": 0,
"s": 0,
"l": 38
},
"count": 556,
"contexts": [
"text",
"border"
]
},
{
"hex": "#373737",
"rgb": {
"r": 55,
"g": 55,
"b": 55,
"a": 1
},
"hsl": {
"h": 0,
"s": 0,
"l": 22
},
"count": 462,
"contexts": [
"text",
"border"
]
},
{
"hex": "#171717",
"rgb": {
"r": 23,
"g": 23,
"b": 23,
"a": 1
},
"hsl": {
"h": 0,
"s": 0,
"l": 9
},
"count": 401,
"contexts": [
"text",
"border",
"background"
]
},
{
"hex": "#ffffff",
"rgb": {
"r": 255,
"g": 255,
"b": 255,
"a": 1
},
"hsl": {
"h": 0,
"s": 0,
"l": 100
},
"count": 242,
"contexts": [
"background",
"border",
"text"
]
},
{
"hex": "#e5e5e5",
"rgb": {
"r": 229,
"g": 229,
"b": 229,
"a": 1
},
"hsl": {
"h": 0,
"s": 0,
"l": 90
},
"count": 217,
"contexts": [
"border",
"background"
]
},
{
"hex": "#d08728",
"rgb": {
"r": 208,
"g": 135,
"b": 40,
"a": 1
},
"hsl": {
"h": 34,
"s": 68,
"l": 49
},
"count": 8,
"contexts": [
"background"
]
}
]
},
"regions": [],
"componentClusters": [
{
"kind": "button",
"structuralHash": "button>svg",
"instanceCount": 55,
"variants": [
{
"css": {
"background": "rgba(0, 0, 0, 0)",
"color": "rgb(55, 55, 55)",
"padding": "0px 0px 0px 0px",
"borderRadius": "4px",
"border": "0px none rgb(55, 55, 55)",
"fontSize": "13.3333px",
"fontWeight": "400"
},
"instanceCount": 55
}
]
},
{
"kind": "button",
"structuralHash": "button",
"instanceCount": 1,
"variants": [
{
"css": {
"background": "rgb(239, 239, 239)",
"color": "rgb(0, 0, 0)",
"padding": "1px 6px 1px 6px",
"borderRadius": "0px",
"border": "2px outset rgb(0, 0, 0)",
"fontSize": "13.3333px",
"fontWeight": "400"
},
"instanceCount": 1
}
]
}
],
"accessibility": {
"remediation": []
},
"cssHealth": {
"sheets": [
{
"url": "https://fonts.googleapis.com/css?family=Inter:300%7CInter:regular%7CInter:500%7CInter:600%7CInter:700",
"totalBytes": 11585,
"usedBytes": 0,
"unusedBytes": 11585,
"unusedPercent": 100
},
{
"url": "https://coulomb.social/package/run_css/0591b05f69514365ec03deea8134e9c2ff462a44dd0474f9fb551cb47e38e201/coulomb/live/vw_pages/xfalse/xfalse/run.css",
"totalBytes": 228282,
"usedBytes": 45959,
"unusedBytes": 182323,
"unusedPercent": 80
},
{
"url": "https://coulomb.social/vw_pages?resume=1786231781137x912895168994024000",
"totalBytes": 821,
"usedBytes": 0,
"unusedBytes": 821,
"unusedPercent": 100
},
{
"url": "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.0/styles/default.min.css",
"totalBytes": 1144,
"usedBytes": 0,
"unusedBytes": 1144,
"unusedPercent": 100
}
],
"totalBytes": 241832,
"usedBytes": 45959,
"unusedBytes": 195873,
"unusedPercent": 81,
"importantCount": 140,
"duplicates": 6545,
"vendorPrefixes": {
"webkit": 139,
"moz": 436,
"ms": 96,
"o": 34
},
"keyframes": [
{
"name": "highlight-in",
"steps": 1
},
{
"name": "fa-spin",
"steps": 2
}
],
"specificity": {
"max": [
1,
7,
46
],
"average": [
0,
1.84,
0.38
],
"count": 2001
},
"issues": [
"140 !important rules",
"6545 duplicate declarations",
"81% unused CSS"
]
}
}

View file

@ -1,6 +1,12 @@
{
"$description": "Motion tokens extracted by designlang",
"duration": {},
"duration": {
"sm": {
"$value": "250ms",
"$type": "duration",
"ms": 250
}
},
"easing": {},
"spring": {},
"$meta": {

View file

@ -0,0 +1,38 @@
/* Motion CSS generated by designlang (motionlang)
* Source: https://coulomb.social
* 2026-08-08T23:30:22.011Z
*
* <link rel="stylesheet" href="./coulomb.social-motion.css">
* <div class="mo-slide-up"></div>
*/
:root {
--duration-sm: 250ms;
--ease-standard: cubic-bezier(0.25, 0.1, 0.25, 1);
}
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes slide-up { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }
@keyframes scale-in { from { opacity: 0; transform: scale(0.96); } to { opacity: 1; transform: none; } }
@keyframes pop { 0% { transform: scale(0.9); } 60% { transform: scale(1.03); } 100% { transform: scale(1); } }
.mo-animate,
[class^="mo-"], [class*=" mo-"] {
animation-duration: var(--duration-sm, 250ms);
animation-timing-function: var(--ease-standard);
animation-fill-mode: both;
}
.mo-fade-in { animation-name: fade-in; }
.mo-slide-up { animation-name: slide-up; }
.mo-scale-in { animation-name: scale-in; }
.mo-pop { animation-name: pop; animation-timing-function: var(--ease-standard); }
@media (prefers-reduced-motion: reduce) {
*, ::before, ::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}

View file

@ -0,0 +1,70 @@
// Framer Motion presets — generated by designlang (motionlang)
// Source: https://coulomb.social
// 2026-08-08T23:30:22.009Z
//
// import { transitions, variants } from './coulomb.social-motion.framer';
// <motion.div variants={variants.slideUp} initial="hidden" animate="show"
// transition={transitions.base} />
/** Easing curves extracted from the live page, as Framer cubic-bezier arrays. */
export const easings = {
standard: [0.25, 1, 0.5, 1],
};
/** Duration presets (seconds), extracted from the live page. */
export const durations = {
sm: 0.25,
};
/** Spring presets — pass to a Framer Motion `transition` prop. */
export const springs = {
soft: { type: 'spring', stiffness: 320, damping: 30, mass: 1 },
};
/** Ready-to-spread Framer Motion transition objects. */
export const transitions = {
base: { duration: 0.25, ease: easings.standard },
fast: { duration: 0.125, ease: easings.standard },
slow: { duration: 0.450, ease: easings.standard },
spring: springs.soft,
};
/** Common variants wired to the extracted timing. */
export const variants = {
fade: {
hidden: { opacity: 0 },
show: { opacity: 1, transition: transitions.base },
},
slideUp: {
hidden: { opacity: 0, y: 16 },
show: { opacity: 1, y: 0, transition: transitions.base },
},
scaleIn: {
hidden: { opacity: 0, scale: 0.96 },
show: { opacity: 1, scale: 1, transition: transitions.base },
},
pop: {
hidden: { opacity: 0, scale: 0.9 },
show: { opacity: 1, scale: 1, transition: springs.soft },
},
stagger: {
hidden: {},
show: { transition: { staggerChildren: 0.063 } },
},
};
/** Site uses scroll- or view-timeline. Drop-in `whileInView` props. */
export const inView = {
fadeIn: {
initial: variants.fade.hidden,
whileInView: variants.fade.show,
viewport: { once: true, amount: 0.3 },
},
riseIn: {
initial: variants.slideUp.hidden,
whileInView: variants.slideUp.show,
viewport: { once: true, amount: 0.3 },
},
};
export default { easings, durations, springs, transitions, variants, inView };

View file

@ -0,0 +1,49 @@
// GSAP presets — generated by designlang (motionlang)
// Source: https://coulomb.social
// 2026-08-08T23:30:22.015Z
//
// import gsap from 'gsap';
// import { registerEases, reveals } from './coulomb.social-motion.gsap.js';
// registerEases(gsap); // one-time: registers CustomEases
// reveals.slideUp('.card');
/** CustomEase path data extracted from the live page, keyed by family. */
export const eases = {
standard: 'M0,0 C0.25,0.1 0.25,1 1,1',
};
/** Duration presets (seconds), extracted from the live page. */
export const durations = {
sm: 0.25,
};
/** Register every extracted curve as a named GSAP CustomEase. Call once. */
export function registerEases(gsap) {
const CustomEase = gsap.plugins?.CustomEase || (typeof window !== 'undefined' && window.CustomEase);
if (!CustomEase) {
console.warn('[motion.gsap] CustomEase plugin not registered — call gsap.registerPlugin(CustomEase) first.');
return;
}
for (const [name, path] of Object.entries(eases)) CustomEase.create(name, path);
}
/** gsap.from() reveal helpers. Pass any GSAP target + optional vars override. */
export const reveals = {
fadeIn: (target, vars = {}) => gsap.from(target, { opacity: 0, duration: 0.25, ease: 'standard', ...vars }),
slideUp: (target, vars = {}) => gsap.from(target, { opacity: 0, y: 24, duration: 0.25, ease: 'standard', ...vars }),
slideDown: (target, vars = {}) => gsap.from(target, { opacity: 0, y: -24, duration: 0.25, ease: 'standard', ...vars }),
scaleIn: (target, vars = {}) => gsap.from(target, { opacity: 0, scale: 0.96, duration: 0.25, ease: 'standard', ...vars }),
pop: (target, vars = {}) => gsap.from(target, { scale: 0.9, duration: 0.25, ease: 'standard', ...vars }),
};
/** Site uses scroll-/view-timeline. Batch-reveals elements as they enter. */
/** Requires: gsap.registerPlugin(ScrollTrigger). */
export function revealOnScroll(targets, vars = {}) {
return gsap.utils.toArray(targets).map((el) =>
gsap.from(el, {
opacity: 0, y: 24, duration: 0.25, ease: 'standard', ...vars,
scrollTrigger: { trigger: el, start: 'top 85%', toggleActions: 'play none none reverse' },
}));
}
export default { eases, durations, registerEases, reveals };

View file

@ -0,0 +1,138 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>coulomb.social — motion lab · designlang</title>
<style>
:root {
--bg: #0a0a0c; --fg: #f4f4f5; --fg-2: rgba(244,244,245,.62); --fg-3: rgba(244,244,245,.4);
--line: rgba(255,255,255,.08); --accent: #ef4444;
--mono: ui-monospace, 'SF Mono', Menlo, monospace;
--sans: -apple-system, 'Segoe UI', system-ui, sans-serif;
}
* { box-sizing: border-box; }
body { margin: 0; background: var(--bg); color: var(--fg); font-family: var(--sans); }
.ml-wrap { max-width: 1080px; margin: 0 auto; padding: 56px 24px 96px; }
header.ml-h { margin-bottom: 48px; }
.ml-eyebrow { font-family: var(--mono); font-size: 11px; letter-spacing: .18em;
text-transform: uppercase; color: var(--fg-3); margin: 0 0 12px; }
h1.ml-title { font-size: clamp(34px, 6vw, 60px); letter-spacing: -.03em; margin: 0 0 12px; font-weight: 600; }
.ml-sub { color: var(--fg-2); font-size: 16px; max-width: 60ch; margin: 0; }
h2.ml-section { font-size: 22px; letter-spacing: -.01em; margin: 56px 0 20px; font-weight: 600; }
.ml-section-meta { font-family: var(--mono); font-size: 12px; color: var(--fg-3); margin-left: 8px; font-weight: 400; }
.ml-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px; }
.ml-card { border: 1px solid var(--line); border-radius: 14px; padding: 18px; background: rgba(255,255,255,.02); }
.ml-card-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 12px; }
.ml-name { font-family: var(--mono); font-size: 13px; color: var(--fg); }
.ml-count { font-family: var(--mono); font-size: 11px; color: var(--fg-3); }
.ml-curve { display: block; margin: 0 auto 12px; }
.ml-curve-guide { stroke: var(--line); stroke-width: 1; stroke-dasharray: 3 3; }
.ml-curve-path { fill: none; stroke: var(--accent); stroke-width: 2.5; stroke-linecap: round; }
.ml-curve-none { height: 160px; display: flex; align-items: center; justify-content: center;
color: var(--fg-3); font-family: var(--mono); font-size: 12px; }
.ml-raw { display: block; font-family: var(--mono); font-size: 10.5px; color: var(--fg-3);
word-break: break-all; margin-bottom: 14px; }
.ml-demo { height: 8px; border-radius: 999px; background: rgba(255,255,255,.05); position: relative; }
.ml-dot { position: absolute; top: 50%; left: 0; width: 14px; height: 14px; border-radius: 50%;
background: var(--accent); transform: translate(0,-50%);
animation: ml-ride 1.6s infinite alternate; box-shadow: 0 0 12px rgba(239,68,68,.6); }
@keyframes ml-ride { from { left: 0; } to { left: calc(100% - 14px); } }
.ml-durs { display: flex; flex-direction: column; gap: 10px; }
.ml-dur { display: grid; grid-template-columns: 90px 1fr 64px; gap: 14px; align-items: center; }
.ml-dur-name { font-family: var(--mono); font-size: 12px; color: var(--fg-2); }
.ml-dur-track { height: 8px; border-radius: 999px; background: rgba(255,255,255,.05); overflow: hidden; }
.ml-dur-fill { display: block; height: 100%; background: var(--accent); border-radius: 999px;
transform-origin: left; animation: ml-pulse var(--ms) ease-in-out infinite alternate; }
@keyframes ml-pulse { from { opacity: .35; } to { opacity: 1; } }
.ml-dur-ms { font-family: var(--mono); font-size: 12px; color: var(--fg-3); text-align: right; }
.ml-kf { border: 1px solid var(--line); border-radius: 14px; padding: 18px; background: rgba(255,255,255,.02); margin-bottom: 14px; }
.ml-kf-css { font-family: var(--mono); font-size: 11px; color: var(--fg-2); overflow-x: auto; margin: 0; }
.ml-empty { color: var(--fg-3); font-family: var(--mono); font-size: 13px;
border: 1px dashed var(--line); border-radius: 12px; padding: 28px; text-align: center; }
footer.ml-f { margin-top: 72px; padding-top: 24px; border-top: 1px solid var(--line);
font-family: var(--mono); font-size: 11px; color: var(--fg-3); }
footer.ml-f a { color: var(--accent); }
@media (prefers-reduced-motion: reduce) { .ml-dot, .ml-dur-fill { animation: none; } }
</style>
</head>
<body>
<div class="ml-wrap">
<header class="ml-h">
<p class="ml-eyebrow">motionlang · motion lab</p>
<h1 class="ml-title">coulomb.social in motion</h1>
<p class="ml-sub">Every easing curve, duration and keyframe animation designlang read off the live coulomb.social page — drawn, timed and replayed. Generated 2026-08-08.</p>
</header>
<h2 class="ml-section">Easing curves <span class="ml-section-meta">0</span></h2>
<div class="ml-empty">No easing curves detected. Re-run with --interactions to capture hover transitions.</div>
<h2 class="ml-section">Durations <span class="ml-section-meta">1</span></h2>
<div class="ml-durs">
<div class="ml-dur">
<span class="ml-dur-name">sm</span>
<span class="ml-dur-track"><span class="ml-dur-fill" style="--ms:250ms; width:25%"></span></span>
<span class="ml-dur-ms">250ms</span>
</div></div>
<h2 class="ml-section">Keyframe animations <span class="ml-section-meta">15</span></h2>
<article class="ml-kf">
<div class="ml-card-head"><span class="ml-name">@keyframes highlight-in</span></div>
<pre class="ml-kf-css"></pre>
</article>
<article class="ml-kf">
<div class="ml-card-head"><span class="ml-name">@keyframes fa-spin</span></div>
<pre class="ml-kf-css"></pre>
</article>
<article class="ml-kf">
<div class="ml-card-head"><span class="ml-name">@keyframes opacity-70-25-0-13</span></div>
<pre class="ml-kf-css"></pre>
</article>
<article class="ml-kf">
<div class="ml-card-head"><span class="ml-name">@keyframes opacity-70-25-1-13</span></div>
<pre class="ml-kf-css"></pre>
</article>
<article class="ml-kf">
<div class="ml-card-head"><span class="ml-name">@keyframes opacity-70-25-2-13</span></div>
<pre class="ml-kf-css"></pre>
</article>
<article class="ml-kf">
<div class="ml-card-head"><span class="ml-name">@keyframes opacity-70-25-3-13</span></div>
<pre class="ml-kf-css"></pre>
</article>
<article class="ml-kf">
<div class="ml-card-head"><span class="ml-name">@keyframes opacity-70-25-4-13</span></div>
<pre class="ml-kf-css"></pre>
</article>
<article class="ml-kf">
<div class="ml-card-head"><span class="ml-name">@keyframes opacity-70-25-5-13</span></div>
<pre class="ml-kf-css"></pre>
</article>
<article class="ml-kf">
<div class="ml-card-head"><span class="ml-name">@keyframes opacity-70-25-6-13</span></div>
<pre class="ml-kf-css"></pre>
</article>
<article class="ml-kf">
<div class="ml-card-head"><span class="ml-name">@keyframes opacity-70-25-7-13</span></div>
<pre class="ml-kf-css"></pre>
</article>
<article class="ml-kf">
<div class="ml-card-head"><span class="ml-name">@keyframes opacity-70-25-8-13</span></div>
<pre class="ml-kf-css"></pre>
</article>
<article class="ml-kf">
<div class="ml-card-head"><span class="ml-name">@keyframes opacity-70-25-9-13</span></div>
<pre class="ml-kf-css"></pre>
</article>
<footer class="ml-f">
Generated by designlang · motionlang · <a href="https://designlang.app">designlang.app</a> · re-extract with <code>npx designlang coulomb.social --motion</code>
</footer>
</div>
</body>
</html>

View file

@ -0,0 +1,58 @@
// Motion One presets — generated by designlang (motionlang)
// Source: https://coulomb.social
// 2026-08-08T23:30:22.010Z
//
// import { animate } from 'motion';
// import { animations, easings, durations } from './coulomb.social-motion.one.js';
//
// animations.fadeIn('#hero');
// animations.slideUp('.card', { delay: 0.1 });
/** Easing curves extracted from the live page, as Motion One cubic-bezier arrays. */
export const easings = {
standard: [0.25, 0.1, 0.25, 1],
};
/** Duration presets (seconds), extracted from the live page. */
export const durations = {
sm: 0.25,
};
/** Motion One spring options — pass as the `type: 'spring'` block of an animate() call. */
export const springs = {
soft: { type: 'spring', stiffness: 320, damping: 30, mass: 1 },
};
/** No on-page @keyframes were attached to elements; emit empty for shape parity. */
export const keyframes = {};
/** Animate-on-call helpers. Each takes a Motion One target + optional override. */
import { animate } from 'motion';
const _t = { duration: 0.25, easing: easings.standard };
export const animations = {
fadeIn: (target, opts = {}) =>
animate(target, { opacity: [0, 1] }, { ..._t, ...opts }),
fadeOut: (target, opts = {}) =>
animate(target, { opacity: [1, 0] }, { ..._t, ...opts }),
slideUp: (target, opts = {}) =>
animate(target, { opacity: [0, 1], y: [16, 0] }, { ..._t, ...opts }),
slideDown: (target, opts = {}) =>
animate(target, { opacity: [0, 1], y: [-16, 0] }, { ..._t, ...opts }),
scaleIn: (target, opts = {}) =>
animate(target, { opacity: [0, 1], scale: [0.96, 1] }, { ..._t, ...opts }),
pop: (target, opts = {}) =>
animate(target, { scale: [0.9, 1] }, { ...springs.soft, ...opts }),
};
/** Site uses scroll- or view-timeline. Helpers wired to Motion One's `inView` / `scroll`. */
import { inView, scroll } from 'motion';
export const enterOnView = (target, variant = animations.slideUp) =>
inView(target, (el) => { variant(el.target); });
export const parallaxY = (target, distance = 80) =>
scroll(animate(target, { y: [0, -distance] }, { easing: 'linear' }));
export default { easings, durations, springs, keyframes, animations };

View file

@ -0,0 +1,67 @@
// Tailwind motion preset — generated by designlang (motionlang)
// Source: https://coulomb.social
// 2026-08-08T23:30:22.014Z
//
// Merge `extend` into your tailwind.config theme.extend, e.g.:
// const motion = require('./coulomb.social-motion.tailwind');
// module.exports = { theme: { extend: { ...motion.extend } } };
//
// Then: <div class="animate-slide-up" /> or `duration-md ease-spring`.
const extend = {
"transitionDuration": {
"sm": "250ms"
},
"transitionTimingFunction": {
"standard": "cubic-bezier(0.25, 0.1, 0.25, 1)"
},
"keyframes": {
"fade-in": {
"0%": {
"opacity": "0"
},
"100%": {
"opacity": "1"
}
},
"slide-up": {
"0%": {
"opacity": "0",
"transform": "translateY(16px)"
},
"100%": {
"opacity": "1",
"transform": "none"
}
},
"scale-in": {
"0%": {
"opacity": "0",
"transform": "scale(0.96)"
},
"100%": {
"opacity": "1",
"transform": "none"
}
},
"pop": {
"0%": {
"transform": "scale(0.9)"
},
"60%": {
"transform": "scale(1.03)"
},
"100%": {
"transform": "scale(1)"
}
}
},
"animation": {
"fade-in": "fade-in 250ms var(--tw-ease-standard, cubic-bezier(0.25, 0.1, 0.25, 1)) both",
"slide-up": "slide-up 250ms var(--tw-ease-standard, cubic-bezier(0.25, 0.1, 0.25, 1)) both",
"scale-in": "scale-in 250ms var(--tw-ease-standard, cubic-bezier(0.25, 0.1, 0.25, 1)) both",
"pop": "pop 250ms var(--tw-ease-standard, cubic-bezier(0.25, 0.1, 0.25, 1)) both"
}
};
module.exports = { extend };

View file

@ -0,0 +1,44 @@
// Web Animations API presets — generated by designlang (motionlang)
// Source: https://coulomb.social
// 2026-08-08T23:30:22.016Z
//
// Zero-dependency. Runs on the browser-native Element.animate().
// import { animations } from './coulomb.social-motion.waapi.js';
// animations.fadeIn(document.querySelector('#hero'));
// await animations.slideUp(card, { delay: 80 }).finished;
/** Easing curves extracted from the live page, as WAAPI easing strings. */
export const easings = {
standard: 'cubic-bezier(0.25, 0.1, 0.25, 1)',
};
/** Duration presets (milliseconds), extracted from the live page. */
export const durations = {
sm: 250,
};
/** No on-page @keyframes were attached to elements; emit empty for shape parity. */
export const keyframes = {};
/** Honours the user's reduced-motion preference. */
export const prefersReducedMotion = () =>
typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion: reduce)').matches;
const _timing = { duration: 250, easing: easings.standard, fill: 'both' };
function _animate(el, frames, opts = {}) {
const timing = { ..._timing, ...opts };
if (prefersReducedMotion()) timing.duration = 0;
return el.animate(frames, timing);
}
/** Animate-on-call helpers. Each returns the live Animation (await `.finished`). */
export const animations = {
fadeIn: (el, opts = {}) => _animate(el, [{ opacity: 0 }, { opacity: 1 }], opts),
fadeOut: (el, opts = {}) => _animate(el, [{ opacity: 1 }, { opacity: 0 }], opts),
slideUp: (el, opts = {}) => _animate(el, [{ opacity: 0, transform: 'translateY(16px)' }, { opacity: 1, transform: 'translateY(0)' }], opts),
slideDown: (el, opts = {}) => _animate(el, [{ opacity: 0, transform: 'translateY(-16px)' }, { opacity: 1, transform: 'translateY(0)' }], opts),
scaleIn: (el, opts = {}) => _animate(el, [{ opacity: 0, transform: 'scale(0.96)' }, { opacity: 1, transform: 'scale(1)' }], opts),
};
export default { easings, durations, keyframes, animations, prefersReducedMotion };

View file

@ -0,0 +1,433 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Design Language: Research | Coulomb</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
:root {
--bg: #0a0a0a; --bg-card: #141414; --border: #222; --text: #e5e5e5; --text-heading: #fff;
--text-muted: #666; --text-sub: #a0a0a0; --text-dim: #444; --text-faint: #555; --row-border: #1a1a1a;
}
[data-theme="light"] {
--bg: #f5f5f5; --bg-card: #fff; --border: #ddd; --text: #333; --text-heading: #111;
--text-muted: #888; --text-sub: #666; --text-dim: #999; --text-faint: #aaa; --row-border: #e5e5e5;
}
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: var(--bg); color: var(--text); line-height: 1.6; }
.container { max-width: 1200px; margin: 0 auto; padding: 40px 24px; }
.header-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.theme-toggle { background: var(--bg-card); border: 1px solid var(--border); color: var(--text); padding: 6px 14px; border-radius: 8px; cursor: pointer; font-size: 13px; white-space: nowrap; }
h1 { font-size: 36px; font-weight: 700; margin-bottom: 8px; color: var(--text-heading); }
h2 { font-size: 24px; font-weight: 600; margin: 48px 0 20px; color: var(--text-heading); border-bottom: 1px solid var(--border); padding-bottom: 12px; }
h3 { font-size: 16px; font-weight: 600; margin: 24px 0 12px; color: var(--text-sub); text-transform: uppercase; letter-spacing: 0.05em; }
.meta { color: var(--text-muted); font-size: 14px; margin-bottom: 32px; }
.meta span { margin-right: 16px; }
.grid { display: grid; gap: 12px; }
.grid-2 { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); }
@media (max-width: 600px) {
.grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr 1fr; }
h1 { font-size: 24px; }
.container { padding: 20px 12px; }
}
@media (max-width: 380px) {
.grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
}
/* Color swatches */
.swatch { border-radius: 12px; overflow: hidden; background: var(--bg-card); border: 1px solid var(--border); cursor: pointer; position: relative; }
.swatch-color { height: 80px; position: relative; }
.swatch-info { padding: 10px 12px; font-size: 13px; }
.swatch-hex { font-weight: 600; font-family: monospace; color: var(--text-heading); }
.swatch-label { font-size: 11px; color: var(--text-muted); margin-top: 2px; }
.swatch-role { display: inline-block; font-size: 10px; background: var(--border); color: var(--text-sub); padding: 2px 8px; border-radius: 4px; margin-top: 4px; }
.copied-tip { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(0,0,0,0.8); color: #fff; padding: 4px 12px; border-radius: 6px; font-size: 12px; pointer-events: none; opacity: 0; transition: opacity 0.2s; }
.copied-tip.show { opacity: 1; }
/* Type scale */
.type-row { display: flex; align-items: baseline; gap: 16px; padding: 12px 0; border-bottom: 1px solid var(--row-border); }
.type-size { font-family: monospace; color: var(--text-muted); min-width: 60px; font-size: 13px; }
.type-meta { font-size: 12px; color: var(--text-dim); margin-left: auto; font-family: monospace; }
/* Spacing */
.spacing-row { display: flex; align-items: center; gap: 12px; padding: 6px 0; }
.spacing-bar { background: linear-gradient(90deg, #3b82f6, #8b5cf6); border-radius: 4px; height: 24px; min-width: 4px; transition: width 0.3s; }
.spacing-label { font-family: monospace; font-size: 13px; color: var(--text-sub); min-width: 60px; }
/* Shadows */
.shadow-card { background: var(--bg-card); border-radius: 12px; padding: 24px; text-align: center; min-height: 80px; display: flex; align-items: center; justify-content: center; border: 1px solid var(--border); }
.shadow-label { font-size: 12px; color: var(--text); font-family: monospace; }
/* Radii */
.radius-item { width: 60px; height: 60px; background: linear-gradient(135deg, #3b82f6, #8b5cf6); display: flex; align-items: center; justify-content: center; font-size: 11px; color: #fff; font-weight: 600; }
/* Accessibility */
.a11y-score { font-size: 64px; font-weight: 800; }
.a11y-score.good { color: #22c55e; }
.a11y-score.warn { color: #eab308; }
.a11y-score.bad { color: #ef4444; }
.a11y-pair { display: flex; align-items: center; gap: 12px; padding: 10px 16px; background: var(--bg-card); border-radius: 8px; margin-bottom: 6px; border: 1px solid var(--border); flex-wrap: wrap; }
.a11y-sample { width: 120px; padding: 6px 12px; border-radius: 6px; text-align: center; font-size: 14px; font-weight: 500; }
.a11y-ratio { font-family: monospace; font-size: 14px; min-width: 50px; }
.a11y-badge { font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 4px; }
.a11y-badge.pass { background: #22c55e20; color: #22c55e; }
.a11y-badge.fail { background: #ef444420; color: #ef4444; }
/* Components */
.comp-screenshot { border-radius: 8px; border: 1px solid var(--border); max-width: 100%; }
/* Stat cards */
.stats { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px; margin: 24px 0; }
.stat { background: var(--bg-card); border: 1px solid var(--border); border-radius: 12px; padding: 16px; }
.stat-value { font-size: 28px; font-weight: 700; color: var(--text-heading); }
.stat-label { font-size: 12px; color: var(--text-muted); margin-top: 4px; }
.font-tag { display: inline-block; background: #1e1e2e; color: #a78bfa; padding: 4px 10px; border-radius: 6px; font-size: 13px; margin: 4px 4px 4px 0; }
[data-theme="light"] .font-tag { background: #ede9fe; color: #6d28d9; }
</style>
</head>
<body>
<div class="container">
<div class="header-row">
<h1>Research | Coulomb</h1>
<button class="theme-toggle" onclick="toggleTheme()">Toggle Light/Dark</button>
</div>
<div class="meta">
<span>https://coulomb.social</span>
<span>3445 elements</span>
<span>8/9/2026</span>
<span>7 pages crawled</span>
</div>
<div class="stats">
<div class="stat"><div class="stat-value">8</div><div class="stat-label">Colors</div></div>
<div class="stat"><div class="stat-value">4</div><div class="stat-label">Font Families</div></div>
<div class="stat"><div class="stat-value">8</div><div class="stat-label">Spacing Values</div></div>
<div class="stat"><div class="stat-value">2</div><div class="stat-label">Shadows</div></div>
<div class="stat"><div class="stat-value">5</div><div class="stat-label">Border Radii</div></div>
<div class="stat"><div class="stat-value">5</div><div class="stat-label">Components</div></div>
<div class="stat"><div class="stat-value good" style="color: #22c55e">100%</div><div class="stat-label">A11y Score</div></div>
</div>
<!-- Colors -->
<h2>Color Palette</h2>
<h3>Brand Colors</h3>
<div class="grid grid-3">
<div class="swatch">
<div class="swatch-color" style="background:#d08728"></div>
<div class="swatch-info">
<div class="swatch-hex">#d08728</div>
<div class="swatch-label">Primary</div>
<div class="swatch-label">8 uses</div>
</div>
</div>
</div>
<h3>Neutrals</h3>
<div class="grid grid-4">
<div class="swatch">
<div class="swatch-color" style="background:#000000"></div>
<div class="swatch-info">
<div class="swatch-hex">#000000</div>
<div class="swatch-label">5304 uses</div>
</div>
</div>
<div class="swatch">
<div class="swatch-color" style="background:#efefef"></div>
<div class="swatch-info">
<div class="swatch-hex">#efefef</div>
<div class="swatch-label">610 uses</div>
</div>
</div>
<div class="swatch">
<div class="swatch-color" style="background:#616161"></div>
<div class="swatch-info">
<div class="swatch-hex">#616161</div>
<div class="swatch-label">556 uses</div>
</div>
</div>
<div class="swatch">
<div class="swatch-color" style="background:#373737"></div>
<div class="swatch-info">
<div class="swatch-hex">#373737</div>
<div class="swatch-label">462 uses</div>
</div>
</div>
<div class="swatch">
<div class="swatch-color" style="background:#171717"></div>
<div class="swatch-info">
<div class="swatch-hex">#171717</div>
<div class="swatch-label">401 uses</div>
</div>
</div>
<div class="swatch">
<div class="swatch-color" style="background:#ffffff"></div>
<div class="swatch-info">
<div class="swatch-hex">#ffffff</div>
<div class="swatch-label">242 uses</div>
</div>
</div>
<div class="swatch">
<div class="swatch-color" style="background:#e5e5e5"></div>
<div class="swatch-info">
<div class="swatch-hex">#e5e5e5</div>
<div class="swatch-label">217 uses</div>
</div>
</div>
</div>
<h3>Full Palette</h3>
<div class="grid grid-4">
<div class="swatch">
<div class="swatch-color" style="background:#000000"></div>
<div class="swatch-info">
<div class="swatch-hex">#000000</div>
<div class="swatch-label">text, border, background</div>
<div class="swatch-label">5304 uses</div>
</div>
</div>
<div class="swatch">
<div class="swatch-color" style="background:#efefef"></div>
<div class="swatch-info">
<div class="swatch-hex">#efefef</div>
<div class="swatch-label">background</div>
<div class="swatch-label">610 uses</div>
</div>
</div>
<div class="swatch">
<div class="swatch-color" style="background:#616161"></div>
<div class="swatch-info">
<div class="swatch-hex">#616161</div>
<div class="swatch-label">text, border</div>
<div class="swatch-label">556 uses</div>
</div>
</div>
<div class="swatch">
<div class="swatch-color" style="background:#373737"></div>
<div class="swatch-info">
<div class="swatch-hex">#373737</div>
<div class="swatch-label">text, border</div>
<div class="swatch-label">462 uses</div>
</div>
</div>
<div class="swatch">
<div class="swatch-color" style="background:#171717"></div>
<div class="swatch-info">
<div class="swatch-hex">#171717</div>
<div class="swatch-label">text, border, background</div>
<div class="swatch-label">401 uses</div>
</div>
</div>
<div class="swatch">
<div class="swatch-color" style="background:#ffffff"></div>
<div class="swatch-info">
<div class="swatch-hex">#ffffff</div>
<div class="swatch-label">background, border, text</div>
<div class="swatch-label">242 uses</div>
</div>
</div>
<div class="swatch">
<div class="swatch-color" style="background:#e5e5e5"></div>
<div class="swatch-info">
<div class="swatch-hex">#e5e5e5</div>
<div class="swatch-label">border, background</div>
<div class="swatch-label">217 uses</div>
</div>
</div>
<div class="swatch">
<div class="swatch-color" style="background:#d08728"></div>
<div class="swatch-info">
<div class="swatch-hex">#d08728</div>
<div class="swatch-label">background</div>
<div class="swatch-label">8 uses</div>
</div>
</div>
</div>
<!-- Typography -->
<h2>Typography</h2>
<h3>Font Families</h3>
<div>
<span class="font-tag">Helvetica <span style="color:#666">(body, 1739x)</span></span><span class="font-tag">Arial <span style="color:#666">(body, 761x)</span></span><span class="font-tag">Times New Roman <span style="color:#666">(body, 450x)</span></span><span class="font-tag">Inter <span style="color:#666">(body, 397x)</span></span>
</div>
<h3>Type Scale</h3>
<div>
<div class="type-row">
<span class="type-size">50px</span>
<span style="font-size:48px;font-weight:400;color:var(--text-heading)">The quick brown fox</span>
<span class="type-meta">400 / 50px</span>
</div>
<div class="type-row">
<span class="type-size">42px</span>
<span style="font-size:42px;font-weight:700;color:var(--text-heading)">The quick brown fox</span>
<span class="type-meta">700 / normal</span>
</div>
<div class="type-row">
<span class="type-size">24px</span>
<span style="font-size:24px;font-weight:600;color:var(--text-heading)">The quick brown fox</span>
<span class="type-meta">600 / 36px</span>
</div>
<div class="type-row">
<span class="type-size">18px</span>
<span style="font-size:18px;font-weight:600;color:var(--text-heading)">The quick brown fox</span>
<span class="type-meta">600 / 18px</span>
</div>
<div class="type-row">
<span class="type-size">16px</span>
<span style="font-size:16px;font-weight:400;color:var(--text-heading)">The quick brown fox</span>
<span class="type-meta">400 / normal</span>
</div>
<div class="type-row">
<span class="type-size">14px</span>
<span style="font-size:14px;font-weight:500;color:var(--text-heading)">The quick brown fox</span>
<span class="type-meta">500 / 19.6px</span>
</div>
<div class="type-row">
<span class="type-size">13.3333px</span>
<span style="font-size:13.3333px;font-weight:400;color:var(--text-heading)">The quick brown fox</span>
<span class="type-meta">400 / normal</span>
</div>
</div>
<!-- Spacing -->
<h2>Spacing Scale (base: 4px)</h2>
<div>
<div class="spacing-row">
<span class="spacing-label">1px</span>
<div class="spacing-bar" style="width:2px"></div>
</div>
<div class="spacing-row">
<span class="spacing-label">24px</span>
<div class="spacing-bar" style="width:48px"></div>
</div>
<div class="spacing-row">
<span class="spacing-label">32px</span>
<div class="spacing-bar" style="width:64px"></div>
</div>
<div class="spacing-row">
<span class="spacing-label">40px</span>
<div class="spacing-bar" style="width:80px"></div>
</div>
<div class="spacing-row">
<span class="spacing-label">60px</span>
<div class="spacing-bar" style="width:120px"></div>
</div>
<div class="spacing-row">
<span class="spacing-label">80px</span>
<div class="spacing-bar" style="width:160px"></div>
</div>
<div class="spacing-row">
<span class="spacing-label">96px</span>
<div class="spacing-bar" style="width:192px"></div>
</div>
<div class="spacing-row">
<span class="spacing-label">320px</span>
<div class="spacing-bar" style="width:500px"></div>
</div>
</div>
<!-- Shadows -->
<h2>Box Shadows</h2>
<div class="grid grid-3">
<div class="shadow-card" style="box-shadow:rgb(170, 170, 170) 2px 2px 4px 0px">
<span class="shadow-label">sm</span>
</div>
<div class="shadow-card" style="box-shadow:rgba(23, 23, 23, 0.1) 2px 2px 8px 2px">
<span class="shadow-label">md</span>
</div>
</div>
<!-- Border Radii -->
<h2>Border Radii</h2>
<div style="display:flex;gap:16px;flex-wrap:wrap;align-items:end">
<div style="text-align:center">
<div class="radius-item" style="border-radius:4px">4px</div>
<div style="font-size:11px;color:#666;margin-top:6px">sm</div>
</div>
<div style="text-align:center">
<div class="radius-item" style="border-radius:8px">8px</div>
<div style="font-size:11px;color:#666;margin-top:6px">md</div>
</div>
<div style="text-align:center">
<div class="radius-item" style="border-radius:12px">12px</div>
<div style="font-size:11px;color:#666;margin-top:6px">lg</div>
</div>
<div style="text-align:center">
<div class="radius-item" style="border-radius:15px">15px</div>
<div style="font-size:11px;color:#666;margin-top:6px">lg</div>
</div>
<div style="text-align:center">
<div class="radius-item" style="border-radius:20px">20px</div>
<div style="font-size:11px;color:#666;margin-top:6px">xl</div>
</div>
</div>
<!-- Accessibility -->
<h2>Accessibility</h2>
<div style="display:flex;align-items:center;gap:24px;margin-bottom:24px">
<div class="a11y-score good">100%</div>
<div>
<div style="color:#fff;font-weight:600">WCAG Contrast Score</div>
<div style="color:#666;font-size:14px">0 passing / 0 failing color pairs</div>
</div>
</div>
<h3>Color Pair Analysis</h3>
<!-- Component Screenshots -->
</div>
<script>
function toggleTheme() {
const html = document.documentElement;
const current = html.getAttribute('data-theme');
html.setAttribute('data-theme', current === 'light' ? 'dark' : 'light');
}
document.querySelectorAll('.swatch').forEach(el => {
el.addEventListener('click', () => {
const hex = el.querySelector('.swatch-hex');
if (!hex) return;
navigator.clipboard.writeText(hex.textContent).then(() => {
let tip = el.querySelector('.copied-tip');
if (!tip) { tip = document.createElement('div'); tip.className = 'copied-tip'; tip.textContent = 'Copied!'; el.appendChild(tip); }
tip.classList.add('show');
setTimeout(() => tip.classList.remove('show'), 1200);
});
});
});
</script>
</body>
</html>

View file

@ -1,10 +1,10 @@
Create a React artifact that reproduces this brand's design language.
Page intent: landing.
Material language: flat.
Voice: Tone: neutral · Headings: unknown.
Colors to use: #000000, #171717, #d08728, #ffffff, #616161, #e5e5e5.
Voice: Tone: neutral · Headings: unknown · CTA verbs: [object Object], [object Object], [object Object], [object Object], [object Object], [object Object].
Colors to use: #000000, #efefef, #616161, #373737, #171717, #ffffff, #e5e5e5, #d08728.
Fonts: [object Object], [object Object], [object Object], [object Object].
Radius vocabulary: 4, 8.
Radius vocabulary: 4, 8, 12, 15, 20.
Sections:
- hero
- features

View file

@ -0,0 +1,18 @@
# Design brief
Page type: **landing**.
Material language: **flat**.
Voice: Tone: neutral · Headings: unknown · CTA verbs: [object Object], [object Object], [object Object], [object Object], [object Object], [object Object].
## Tokens
```ts
export const tokens = {
colors: ['#000000', '#efefef', '#616161', '#373737', '#171717', '#ffffff', '#e5e5e5', '#d08728'],
fonts: ['[object Object]', '[object Object]', '[object Object]', '[object Object]'],
radii: ['4', '8', '12', '15', '20'],
shadows: ['rgb(170, 170, 170) 2px 2px 4px 0px', 'rgba(23, 23, 23, 0.1) 2px 2px 8px 2px'],
};
```
## Sections
- hero
- features
- cta
- footer

View file

@ -0,0 +1,12 @@
Clone the design language of this landing page and build a fresh equivalent.
Visual feel: flat. Tone: neutral · Headings: unknown · CTA verbs: [object Object], [object Object], [object Object], [object Object], [object Object], [object Object]
Primary palette: #000000, #efefef, #616161, #373737, #171717.
Typography: [object Object], [object Object], [object Object], [object Object].
Corner radius vocabulary: 4, 8, 12, 15, 20.
Shadow vocabulary: rgb(170, 170, 170) 2px 2px 4px 0px | rgba(23, 23, 23, 0.1) 2px 2px 8px 2px.
Page structure:
- hero
- features
- social proof
- cta
- footer

View file

@ -0,0 +1,28 @@
# Recipe: button
Build one button component that matches this brand.
Palette: #000000, #efefef, #616161, #373737, #171717, #ffffff
Typography: [object Object], [object Object], [object Object], [object Object]
Material: flat
Signals: Radius: 4, 8, 12, 15, 20 · Shadows: rgb(170, 170, 170) 2px 2px 4px 0px | rgba(23, 23, 23, 0.1) 2px 2px 8px 2px
## Anatomy (detected)
```json
{
"kind": "button",
"structuralHash": "button",
"instanceCount": 1,
"variants": [
{
"css": {
"background": "rgb(239, 239, 239)",
"color": "rgb(0, 0, 0)",
"padding": "1px 6px 1px 6px",
"borderRadius": "0px",
"border": "2px outset rgb(0, 0, 0)",
"fontSize": "13.3333px",
"fontWeight": "400"
},
"instanceCount": 1
}
]
}
```

View file

@ -1,17 +1,19 @@
Build a landing page with this exact visual language.
COLORS:
#000000
#171717
#d08728
#ffffff
#efefef
#616161
#373737
#171717
#ffffff
#e5e5e5
#d08728
FONTS: [object Object], [object Object], [object Object], [object Object]
SPACING: 2, 32, 68
RADIUS: 4, 8
SHADOWS: rgb(97, 97, 97) 2px 2px 8px 0px
SPACING: 1, 24, 32, 40, 60, 80, 96, 320
RADIUS: 4, 8, 12, 15, 20
SHADOWS: rgb(170, 170, 170) 2px 2px 4px 0px | rgba(23, 23, 23, 0.1) 2px 2px 8px 2px
MATERIAL LANGUAGE: flat
VOICE: Tone: neutral · Headings: unknown
VOICE: Tone: neutral · Headings: unknown · CTA verbs: [object Object], [object Object], [object Object], [object Object], [object Object], [object Object]
SECTIONS (in order):
- hero
- features

View file

@ -0,0 +1,81 @@
/*
Brand-aware reset generated by designlang
Research | Coulomb
2026-08-08T23:30:22.005Z
*/
*, *::before, *::after { box-sizing: border-box; }
html, body, h1, h2, h3, h4, h5, h6, p, ul, ol, li, blockquote, figure,
form, fieldset, table, hr {
margin: 0;
padding: 0;
}
html {
-webkit-text-size-adjust: 100%;
-moz-text-size-adjust: 100%;
text-size-adjust: 100%;
-webkit-tap-highlight-color: transparent;
font-family: "Helvetica", system-ui, -apple-system, 'Segoe UI', sans-serif;
font-size: 16px;
line-height: 1.5;
}
body {
background-color: #ffffff;
color: #000000;
font-weight: 400;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
}
h1, h2, h3, h4, h5, h6 {
font-family: "Helvetica", system-ui, -apple-system, sans-serif;
font-weight: 600;
line-height: 1.15;
letter-spacing: -0.015em;
}
a {
color: #d08728;
text-decoration: none;
background-color: transparent;
}
a:hover { text-decoration: underline; }
a:focus-visible { outline: 2px solid #d08728; outline-offset: 2px; border-radius: 4px; }
img, picture, video, canvas, svg {
display: block;
max-width: 100%;
height: auto;
}
input, textarea, select, button {
font: inherit;
color: inherit;
}
button { cursor: pointer; background: none; border: 0; padding: 0; }
code, pre, kbd, samp {
font-family: ui-monospace, ui-monospace, 'SF Mono', Menlo, monospace;
}
hr {
border: 0;
border-top: 1px solid #e5e5e5;
}
::selection {
background: #d08728;
color: #ffffff;
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.001ms !important;
transition-duration: 0.001ms !important;
scroll-behavior: auto !important;
}
}

View file

@ -0,0 +1,15 @@
# Multi-route Token Reconciliation
- Routes crawled: **7**
- Shared tokens: **17**
- Total unique tokens across routes: **41**
- Cross-route drift entries: **148**
## Per-route contributions
- `/` (index): 0 added, 19 changed
- `/pg_chunk/1786106348475x662489469743530000` (pg-chunk-1786106348475x662489469743530000): 1 added, 22 changed
- `/pg_chunk/1767965374100x901547861536145400` (pg-chunk-1767965374100x901547861536145400): 0 added, 21 changed
- `/pg_chunk/1785501151364x921456713843343400` (pg-chunk-1785501151364x921456713843343400): 0 added, 21 changed
- `/pg_chunk/1784904857383x503270614975381500` (pg-chunk-1784904857383x503270614975381500): 0 added, 22 changed
- `/pg_chunk/1785501127011x363256181345746940` (pg-chunk-1785501127011x363256181345746940): 0 added, 21 changed
- `/pg_chunk/1784305925912x322414739506593800` (pg-chunk-1784305925912x322414739506593800): 0 added, 22 changed

View file

@ -0,0 +1,40 @@
{
"openGraph": {
"title": "An Ideas Come To Life Community!",
"site_name": "Coulomb Social",
"description": "A tool to brainstorm, discuss, refine implement and promote ideas.\nA social network for building stuff and influencing how stuff is built.\nA marketplace for challenges, methods and solutions.\nA platform to monetize curiosity.",
"image": "https://13a55be71f3a6a4c9ea356833df823c4.cdn.bubble.io/cdn-cgi/image/w=,h=,f=auto,dpr=1,fit=contain/f1750630995632x205964292977919070/Coulomb%20Logo.png",
"url": "https://coulomb.social/vw_pages?resume=1786231781137x912895168994024000",
"type": "website"
},
"twitter": {
"title": "An Ideas Come To Life Community!",
"site_name": "Coulomb Social",
"description": "A tool to brainstorm, discuss, refine implement and promote ideas.\nA social network for building stuff and influencing how stuff is built.\nA marketplace for challenges, methods and solutions.\nA platform to monetize curiosity.",
"image:src": "https://13a55be71f3a6a4c9ea356833df823c4.cdn.bubble.io/cdn-cgi/image/w=,h=,f=auto,dpr=1,fit=contain/f1750630995632x205964292977919070/Coulomb%20Logo.png",
"card": "summary_large_image"
},
"description": "A tool to brainstorm, discuss, refine implement and promote ideas.\nA social network for building stuff and influencing how stuff is built.\nA marketplace for challenges, methods and solutions.\nA platform to monetize curiosity.",
"canonical": null,
"themeColor": null,
"viewport": "width=device-width,initial-scale=1.0",
"favicons": [
{
"rel": "icon",
"href": "https://13a55be71f3a6a4c9ea356833df823c4.cdn.bubble.io/cdn-cgi/image/w=128,h=,f=auto,dpr=1,fit=contain/f1738533145653x421346820735372100/Coulomb%20Logo.png",
"sizes": "",
"type": "image/png"
}
],
"manifest": null,
"structuredData": [],
"score": {
"hasOg": true,
"hasTwitter": true,
"hasDescription": true,
"hasCanonical": false,
"hasStructuredData": false,
"hasFavicon": true,
"hasThemeColor": false
}
}

View file

@ -0,0 +1,15 @@
/* shadcn/ui Theme — extracted from https://coulomb.social */
/* Paste into your globals.css */
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 0 0% 0%;
--primary: 34 68% 49%;
--primary-foreground: 0 0% 100%;
--muted: 0 0% 90%;
--muted-foreground: 0 0% 0%;
--border: 0 0% 9%;
--radius: 8px;
}
}

View file

@ -0,0 +1,12 @@
{
"cms": [
"webflow",
"bubble"
],
"analytics": [],
"experimentation": [],
"signals": {
"scriptCount": 10,
"metaCount": 15
}
}

View file

@ -0,0 +1,55 @@
/*
Tailwind v4 @theme generated by designlang
site: Research | Coulomb
2026-08-08T23:30:22.003Z
Drop this above `@import "tailwindcss";`.
*/
@import "tailwindcss";
@theme {
--color-primary-50: hsl(34 68% 97%);
--color-primary-100: hsl(34 68% 94%);
--color-primary-200: hsl(34 68% 86%);
--color-primary-300: hsl(34 68% 76%);
--color-primary-400: hsl(34 68% 64%);
--color-primary-500: hsl(34 68% 50%);
--color-primary-600: hsl(34 68% 40%);
--color-primary-700: hsl(34 68% 32%);
--color-primary-800: hsl(34 68% 24%);
--color-primary-900: hsl(34 68% 16%);
--color-primary-950: hsl(34 68% 10%);
--color-primary: #d08728;
--color-neutral-50: #000000;
--color-neutral-100: #efefef;
--color-neutral-200: #616161;
--color-neutral-300: #373737;
--color-neutral-400: #171717;
--color-neutral-500: #ffffff;
--color-neutral-600: #e5e5e5;
--color-background: #ffffff;
--color-foreground: #000000;
--font-sans: "Helvetica", system-ui, sans-serif;
--spacing-1: 1px;
--spacing-2: 24px;
--spacing-3: 32px;
--spacing-4: 40px;
--spacing-5: 60px;
--spacing-6: 80px;
--spacing-7: 96px;
--spacing-8: 320px;
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-xl: 15px;
--radius-2xl: 20px;
--shadow-sm: rgb(170, 170, 170) 2px 2px 4px 0px;
--shadow-md: rgba(23, 23, 23, 0.1) 2px 2px 8px 2px;
--animate-duration-fast: undefined;
}
/* Optional base reset that maps body/heading to the extracted tokens. */
@layer base {
html { font-family: var(--font-sans); }
body { background-color: var(--color-background); color: var(--color-foreground, currentColor); }
}

View file

@ -18,36 +18,22 @@ export default {
DEFAULT: '#d08728'
},
'neutral-50': '#000000',
'neutral-100': '#171717',
'neutral-200': '#ffffff',
'neutral-300': '#616161',
'neutral-400': '#e5e5e5',
'neutral-100': '#efefef',
'neutral-200': '#616161',
'neutral-300': '#373737',
'neutral-400': '#171717',
'neutral-500': '#ffffff',
'neutral-600': '#e5e5e5',
background: '#ffffff',
foreground: '#000000'
},
fontFamily: {
body: [
'Arial',
'sans-serif'
],
font2: [
'Inter',
'sans-serif'
]
},
fontSize: {
'8': [
'8px',
{
lineHeight: '11.2px'
}
],
'12': [
'12px',
{
lineHeight: '16.8px'
}
],
'14': [
'14px',
{
@ -63,19 +49,25 @@ export default {
'18': [
'18px',
{
lineHeight: '25.2px'
lineHeight: '18px'
}
],
'32': [
'32px',
'24': [
'24px',
{
lineHeight: '44.8px'
lineHeight: '36px'
}
],
'48': [
'48px',
'42': [
'42px',
{
lineHeight: '67.2px'
lineHeight: 'normal'
}
],
'50': [
'50px',
{
lineHeight: '50px'
}
],
'13.3333': [
@ -86,23 +78,34 @@ export default {
]
},
spacing: {
'1': '2px',
'16': '32px',
'34': '68px'
'6': '24px',
'8': '32px',
'10': '40px',
'15': '60px',
'20': '80px',
'24': '96px',
'80': '320px',
'1px': '1px'
},
borderRadius: {
sm: '4px',
md: '8px'
md: '8px',
lg: '15px',
xl: '20px'
},
boxShadow: {
md: 'rgb(97, 97, 97) 2px 2px 8px 0px'
sm: 'rgb(170, 170, 170) 2px 2px 4px 0px',
md: 'rgba(23, 23, 23, 0.1) 2px 2px 8px 2px'
},
transitionDuration: {
'250': '0.25s'
},
container: {
center: true,
padding: '32px'
padding: '0px'
},
maxWidth: {
container: '1080px'
container: '1200px'
}
},
},

View file

@ -14,30 +14,39 @@
neutral200: string;
neutral300: string;
neutral400: string;
neutral500: string;
neutral600: string;
* };
* fonts: {
body: string;
* };
* fontSizes: {
'8': string;
'12': string;
'14': string;
'16': string;
'18': string;
'32': string;
'48': string;
'24': string;
'42': string;
'50': string;
'13.3333': string;
* };
* space: {
'2': string;
'1': string;
'24': string;
'32': string;
'68': string;
'40': string;
'60': string;
'80': string;
'96': string;
'320': string;
* };
* radii: {
sm: string;
md: string;
lg: string;
xl: string;
* };
* shadows: {
sm: string;
md: string;
* };
* states: {
@ -55,35 +64,44 @@ export const theme = {
"background": "#ffffff",
"foreground": "#000000",
"neutral50": "#000000",
"neutral100": "#171717",
"neutral200": "#ffffff",
"neutral300": "#616161",
"neutral400": "#e5e5e5"
"neutral100": "#efefef",
"neutral200": "#616161",
"neutral300": "#373737",
"neutral400": "#171717",
"neutral500": "#ffffff",
"neutral600": "#e5e5e5"
},
"fonts": {
"body": "'Arial', sans-serif"
"body": "'Inter', sans-serif"
},
"fontSizes": {
"8": "8px",
"12": "12px",
"14": "14px",
"16": "16px",
"18": "18px",
"32": "32px",
"48": "48px",
"24": "24px",
"42": "42px",
"50": "50px",
"13.3333": "13.3333px"
},
"space": {
"2": "2px",
"1": "1px",
"24": "24px",
"32": "32px",
"68": "68px"
"40": "40px",
"60": "60px",
"80": "80px",
"96": "96px",
"320": "320px"
},
"radii": {
"sm": "4px",
"md": "8px"
"md": "8px",
"lg": "15px",
"xl": "20px"
},
"shadows": {
"md": "rgb(97, 97, 97) 2px 2px 8px 0px"
"sm": "rgb(170, 170, 170) 2px 2px 4px 0px",
"md": "rgba(23, 23, 23, 0.1) 2px 2px 8px 2px"
},
"states": {
"hover": {
@ -111,19 +129,24 @@ export const muiTheme = {
},
"background": {
"default": "#ffffff",
"paper": "#616161"
"paper": "#e5e5e5"
},
"text": {
"primary": "#000000",
"secondary": "#ffffff"
"secondary": "#171717"
}
},
"typography": {
"fontFamily": "'Times New Roman', sans-serif",
"fontFamily": "'Helvetica', sans-serif",
"h1": {
"fontSize": "32px",
"fontSize": "42px",
"fontWeight": "700",
"lineHeight": "normal"
},
"h2": {
"fontSize": "24px",
"fontWeight": "600",
"lineHeight": "44.8px"
"lineHeight": "36px"
},
"body1": {
"fontSize": "16px",
@ -131,16 +154,17 @@ export const muiTheme = {
"lineHeight": "normal"
},
"body2": {
"fontSize": "13.3333px",
"fontWeight": "400",
"lineHeight": "normal"
"fontSize": "14px",
"fontWeight": "500",
"lineHeight": "19.6px"
}
},
"shape": {
"borderRadius": 8
},
"shadows": [
"rgb(97, 97, 97) 2px 2px 8px 0px"
"rgb(170, 170, 170) 2px 2px 4px 0px",
"rgba(23, 23, 23, 0.1) 2px 2px 8px 2px"
]
};

View file

@ -0,0 +1,82 @@
{
"url": "https://coulomb.social",
"path": "/",
"added": {},
"changed": {
"primitive": {
"color": {
"brand": {
"primary": {
"$value": "#000000"
}
},
"neutral": {
"n200": {
"$value": "#373737"
},
"n300": {
"$value": "#616161"
},
"n400": {
"$value": "#171717"
},
"n500": {
"$value": "#efefef"
},
"n600": {
"$value": "#ffffff"
},
"n700": {
"$value": "#e5e5e5"
}
},
"background": {
"bg1": {
"$value": "#e5e5e5"
}
},
"text": {
"text2": {
"$value": "#373737"
},
"text3": {
"$value": "#616161"
}
}
},
"spacing": {
"s1": {
"$value": "24px"
},
"s2": {
"$value": "32px"
},
"s3": {
"$value": "40px"
},
"s4": {
"$value": "82px"
},
"s5": {
"$value": "96px"
}
},
"radius": {
"r3": {
"$value": "20px"
}
},
"fontFamily": {
"f1": {
"$value": "Inter"
},
"f2": {
"$value": "Arial"
},
"f3": {
"$value": "Times New Roman"
}
}
}
}
}

View file

@ -0,0 +1,88 @@
{
"url": "https://coulomb.social/pg_chunk/1767965374100x901547861536145400",
"path": "/pg_chunk/1767965374100x901547861536145400",
"added": {},
"changed": {
"primitive": {
"color": {
"brand": {
"primary": {
"$value": "#d08728"
}
},
"neutral": {
"n200": {
"$value": "#efefef"
},
"n300": {
"$value": "#e5e5e5"
},
"n400": {
"$value": "#616161"
},
"n500": {
"$value": "#171717"
},
"n600": {
"$value": "#ffffff"
},
"n700": {
"$value": "#373737"
}
},
"background": {
"bg1": {
"$value": "#171717"
},
"bg2": {
"$value": "#f5f5f5"
},
"bg3": {
"$value": "#e5e5e5"
}
},
"text": {
"text2": {
"$value": "#616161"
},
"text3": {
"$value": "#373737"
}
}
},
"spacing": {
"s1": {
"$value": "60px"
},
"s2": {
"$value": "80px"
},
"s3": {
"$value": "96px"
},
"s4": {
"$value": "320px"
}
},
"radius": {
"r3": {
"$value": "15px"
},
"r4": {
"$value": "20px"
}
},
"fontFamily": {
"f1": {
"$value": "Arial"
},
"f2": {
"$value": "Times New Roman"
},
"f3": {
"$value": "Inter"
}
}
}
}
}

View file

@ -0,0 +1,91 @@
{
"url": "https://coulomb.social/pg_chunk/1784305925912x322414739506593800",
"path": "/pg_chunk/1784305925912x322414739506593800",
"added": {},
"changed": {
"primitive": {
"color": {
"brand": {
"primary": {
"$value": "#d08728"
}
},
"neutral": {
"n200": {
"$value": "#efefef"
},
"n300": {
"$value": "#616161"
},
"n400": {
"$value": "#373737"
},
"n500": {
"$value": "#e5e5e5"
},
"n600": {
"$value": "#171717"
},
"n700": {
"$value": "#ffffff"
}
},
"background": {
"bg1": {
"$value": "#171717"
},
"bg2": {
"$value": "#f5f5f5"
},
"bg3": {
"$value": "#e5e5e5"
}
},
"text": {
"text2": {
"$value": "#616161"
},
"text3": {
"$value": "#373737"
},
"text4": {
"$value": "#ffffff"
}
}
},
"spacing": {
"s1": {
"$value": "60px"
},
"s2": {
"$value": "80px"
},
"s3": {
"$value": "96px"
},
"s4": {
"$value": "320px"
}
},
"radius": {
"r3": {
"$value": "15px"
},
"r4": {
"$value": "20px"
}
},
"fontFamily": {
"f1": {
"$value": "Arial"
},
"f2": {
"$value": "Times New Roman"
},
"f3": {
"$value": "Inter"
}
}
}
}
}

View file

@ -0,0 +1,91 @@
{
"url": "https://coulomb.social/pg_chunk/1784904857383x503270614975381500",
"path": "/pg_chunk/1784904857383x503270614975381500",
"added": {},
"changed": {
"primitive": {
"color": {
"brand": {
"primary": {
"$value": "#d08728"
}
},
"neutral": {
"n200": {
"$value": "#efefef"
},
"n300": {
"$value": "#616161"
},
"n400": {
"$value": "#373737"
},
"n500": {
"$value": "#e5e5e5"
},
"n600": {
"$value": "#171717"
},
"n700": {
"$value": "#ffffff"
}
},
"background": {
"bg1": {
"$value": "#171717"
},
"bg2": {
"$value": "#f5f5f5"
},
"bg3": {
"$value": "#e5e5e5"
}
},
"text": {
"text2": {
"$value": "#616161"
},
"text3": {
"$value": "#373737"
},
"text4": {
"$value": "#ffffff"
}
}
},
"spacing": {
"s1": {
"$value": "60px"
},
"s2": {
"$value": "80px"
},
"s3": {
"$value": "96px"
},
"s4": {
"$value": "320px"
}
},
"radius": {
"r3": {
"$value": "15px"
},
"r4": {
"$value": "20px"
}
},
"fontFamily": {
"f1": {
"$value": "Arial"
},
"f2": {
"$value": "Times New Roman"
},
"f3": {
"$value": "Inter"
}
}
}
}
}

View file

@ -0,0 +1,88 @@
{
"url": "https://coulomb.social/pg_chunk/1785501127011x363256181345746940",
"path": "/pg_chunk/1785501127011x363256181345746940",
"added": {},
"changed": {
"primitive": {
"color": {
"brand": {
"primary": {
"$value": "#d08728"
}
},
"neutral": {
"n200": {
"$value": "#efefef"
},
"n300": {
"$value": "#e5e5e5"
},
"n400": {
"$value": "#616161"
},
"n500": {
"$value": "#171717"
},
"n600": {
"$value": "#ffffff"
},
"n700": {
"$value": "#373737"
}
},
"background": {
"bg1": {
"$value": "#171717"
},
"bg2": {
"$value": "#f5f5f5"
},
"bg3": {
"$value": "#e5e5e5"
}
},
"text": {
"text2": {
"$value": "#616161"
},
"text3": {
"$value": "#373737"
}
}
},
"spacing": {
"s1": {
"$value": "60px"
},
"s2": {
"$value": "80px"
},
"s3": {
"$value": "96px"
},
"s4": {
"$value": "320px"
}
},
"radius": {
"r3": {
"$value": "15px"
},
"r4": {
"$value": "20px"
}
},
"fontFamily": {
"f1": {
"$value": "Arial"
},
"f2": {
"$value": "Times New Roman"
},
"f3": {
"$value": "Inter"
}
}
}
}
}

View file

@ -0,0 +1,88 @@
{
"url": "https://coulomb.social/pg_chunk/1785501151364x921456713843343400",
"path": "/pg_chunk/1785501151364x921456713843343400",
"added": {},
"changed": {
"primitive": {
"color": {
"brand": {
"primary": {
"$value": "#d08728"
}
},
"neutral": {
"n200": {
"$value": "#efefef"
},
"n300": {
"$value": "#e5e5e5"
},
"n400": {
"$value": "#171717"
},
"n500": {
"$value": "#616161"
},
"n600": {
"$value": "#ffffff"
},
"n700": {
"$value": "#373737"
}
},
"background": {
"bg1": {
"$value": "#171717"
},
"bg2": {
"$value": "#f5f5f5"
},
"bg3": {
"$value": "#e5e5e5"
}
},
"text": {
"text2": {
"$value": "#616161"
},
"text3": {
"$value": "#373737"
},
"text4": {
"$value": "#ffffff"
}
}
},
"spacing": {
"s1": {
"$value": "60px"
},
"s2": {
"$value": "80px"
},
"s3": {
"$value": "96px"
},
"s4": {
"$value": "320px"
}
},
"radius": {
"r3": {
"$value": "15px"
}
},
"fontFamily": {
"f1": {
"$value": "Arial"
},
"f2": {
"$value": "Times New Roman"
},
"f3": {
"$value": "Inter"
}
}
}
}
}

View file

@ -0,0 +1,99 @@
{
"url": "https://coulomb.social/pg_chunk/1786106348475x662489469743530000",
"path": "/pg_chunk/1786106348475x662489469743530000",
"added": {
"primitive": {
"spacing": {
"s6": {
"$value": "320px"
}
}
}
},
"changed": {
"primitive": {
"color": {
"brand": {
"primary": {
"$value": "#d08728"
}
},
"neutral": {
"n200": {
"$value": "#efefef"
},
"n300": {
"$value": "#616161"
},
"n400": {
"$value": "#171717"
},
"n500": {
"$value": "#ffffff"
},
"n600": {
"$value": "#373737"
},
"n700": {
"$value": "#e5e5e5"
}
},
"background": {
"bg1": {
"$value": "#171717"
},
"bg2": {
"$value": "#f5f5f5"
},
"bg3": {
"$value": "#e5e5e5"
}
},
"text": {
"text2": {
"$value": "#616161"
},
"text3": {
"$value": "#373737"
}
}
},
"spacing": {
"s1": {
"$value": "24px"
},
"s2": {
"$value": "32px"
},
"s3": {
"$value": "40px"
},
"s4": {
"$value": "80px"
},
"s5": {
"$value": "96px"
}
},
"radius": {
"r3": {
"$value": "15px"
},
"r4": {
"$value": "20px"
}
},
"fontFamily": {
"f1": {
"$value": "Arial"
},
"f2": {
"$value": "Times New Roman"
},
"f3": {
"$value": "Inter"
}
}
}
}
}

View file

@ -0,0 +1,92 @@
{
"primitive": {
"color": {
"neutral": {
"n100": {
"$value": "#000000"
}
},
"background": {
"bg0": {
"$value": "#ffffff"
}
},
"text": {
"text0": {
"$value": "#000000"
},
"text1": {
"$value": "#171717"
}
}
},
"spacing": {
"s0": {
"$value": "1px"
}
},
"radius": {
"r0": {
"$value": "4px"
},
"r1": {
"$value": "8px"
},
"r2": {
"$value": "12px"
}
},
"shadow": {
"sh0": {
"$value": "rgb(170, 170, 170) 2px 2px 4px 0px"
},
"sh1": {
"$value": "rgba(23, 23, 23, 0.1) 2px 2px 8px 2px"
}
},
"fontFamily": {
"f0": {
"$value": "Helvetica"
}
}
},
"semantic": {
"color": {
"action": {
"primary": {
"$value": "{primitive.color.brand.primary}"
}
},
"surface": {
"default": {
"$value": "{primitive.color.background.bg0}"
}
},
"text": {
"body": {
"$value": "{primitive.color.text.text0}"
}
}
},
"typography": {
"body": {
"$value": {
"fontFamily": "Helvetica",
"fontSize": "50px",
"fontWeight": "400",
"lineHeight": "50px"
}
}
},
"radius": {
"control": {
"$value": "{primitive.radius.r0}"
}
},
"shadow": {
"elevated": {
"$value": "{primitive.shadow.sh0}"
}
}
}
}

View file

@ -0,0 +1,49 @@
// Auto-generated by designlang. Do not edit by hand.
// Re-extract with `npx designlang <url>` to refresh.
//
// Import next to your token JSON to get type-safe access:
//
// import type { ColorToken, SpacingToken } from './<host>-tokens';
// import tokens from './<host>-design-tokens.json';
//
// Source: https://coulomb.social
// Generated: 2026-08-08T23:30:22.004Z
export type Hex = `#${string}`;
export type Px = `${number}px`;
export type Ms = `${number}ms`;
export type ColorRole = 'primary';
export type ColorHex = '#000000' | '#efefef' | '#616161' | '#373737' | '#171717' | '#ffffff' | '#e5e5e5' | '#d08728';
export type ColorToken = ColorRole | ColorHex;
export type FontFamilyToken = 'Helvetica' | 'Arial' | 'Times New Roman' | 'Inter';
export type FontSizeToken = never;
export type FontWeightToken = '400' | '500' | '600' | '700';
export type SpacingToken = '1px' | '24px' | '32px' | '40px' | '60px' | '80px' | '96px' | '320px';
export type RadiusToken = '4px' | '8px' | '12px' | '15px' | '20px';
export type DurationToken = '250ms';
export type EasingToken = never;
export type MaterialLanguage = 'flat';
export interface DesignTokens {
color: { [role in ColorRole]: ColorHex };
typography: {
family: FontFamilyToken;
size: FontSizeToken;
weight: FontWeightToken;
};
spacing: ReadonlyArray<SpacingToken>;
radius: ReadonlyArray<RadiusToken>;
motion: {
duration: ReadonlyArray<DurationToken>;
easing: ReadonlyArray<EasingToken>;
};
}
declare const tokens: DesignTokens;
export default tokens;

View file

@ -4,48 +4,61 @@
/* Colors — Neutrals */
--color-neutral-50: #000000;
--color-neutral-100: #171717;
--color-neutral-200: #ffffff;
--color-neutral-300: #616161;
--color-neutral-400: #e5e5e5;
--color-neutral-100: #efefef;
--color-neutral-200: #616161;
--color-neutral-300: #373737;
--color-neutral-400: #171717;
--color-neutral-500: #ffffff;
--color-neutral-600: #e5e5e5;
/* Colors — Backgrounds */
--color-bg: #ffffff;
--color-bg-1: #616161;
--color-bg-1: #e5e5e5;
--color-bg-2: #171717;
--color-bg-3: #f5f5f5;
/* Colors — Text */
--color-text: #000000;
--color-text-1: #ffffff;
--color-text-2: #171717;
--color-text-3: #d08728;
--color-text-1: #171717;
--color-text-2: #373737;
--color-text-3: #616161;
--color-text-4: #ffffff;
/* Typography — Families */
--font-body: 'Times New Roman', sans-serif;
--font-body: 'Helvetica', sans-serif;
--font-font-2: 'Inter', sans-serif;
--font-body: 'Arial', sans-serif;
--font-body: 'Times New Roman', sans-serif;
--font-body: 'Inter', sans-serif;
/* Typography — Scale */
--font-size-48: 48px;
--font-size-32: 32px;
--font-size-50: 50px;
--font-size-42: 42px;
--font-size-24: 24px;
--font-size-18: 18px;
--font-size-16: 16px;
--font-size-14: 14px;
--font-size-13.3333: 13.3333px;
--font-size-12: 12px;
--font-size-8: 8px;
/* Spacing */
--spacing-2: 2px;
--spacing-1: 1px;
--spacing-24: 24px;
--spacing-32: 32px;
--spacing-68: 68px;
--spacing-40: 40px;
--spacing-60: 60px;
--spacing-80: 80px;
--spacing-96: 96px;
--spacing-320: 320px;
/* Border Radius */
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-lg: 15px;
--radius-xl: 20px;
/* Box Shadows */
--shadow-md: rgb(97, 97, 97) 2px 2px 8px 0px;
--shadow-sm: rgb(170, 170, 170) 2px 2px 4px 0px;
--shadow-md: rgba(23, 23, 23, 0.1) 2px 2px 8px 2px;
/* Original Site Variables */
/* — colors — */

View file

@ -0,0 +1,53 @@
{
"materialLanguage": {
"label": "flat",
"confidence": 0,
"signals": [],
"metrics": {
"saturation": 0.101,
"shadowProfile": "soft",
"avgShadowBlur": 0,
"maxShadowBlur": 0,
"insetShadows": 0,
"avgRadius": 11.8,
"maxRadius": 20,
"hasPill": false,
"hasBackdropBlur": false,
"gradientCount": 0
},
"alternates": []
},
"imageryStyle": {
"label": "mixed",
"confidence": 0,
"counts": {
"total": 29,
"svg": 0,
"icon": 1,
"hero": 0,
"screenshot": 0,
"photoLike": 0
},
"dominantAspect": "square-ish",
"radiusProfile": "soft",
"alternates": [],
"signals": []
},
"backgroundPatterns": {
"labels": [
"plain"
],
"counts": {
"noise": 0,
"dotGrid": 0,
"lineGrid": 0,
"meshCount": 0,
"svgPattern": 0
},
"gradientTotals": {
"radial": 0,
"linear": 0
},
"samples": []
}
}

View file

@ -0,0 +1,71 @@
{
"tone": "neutral",
"pronoun": "third-person",
"headingStyle": "unknown",
"headingLengthClass": "tight",
"ctaVerbs": [
{
"value": "content",
"count": 25
},
{
"value": "favorite",
"count": 25
},
{
"value": "format",
"count": 1
},
{
"value": "filter",
"count": 1
},
{
"value": "add",
"count": 1
},
{
"value": "arrow",
"count": 1
},
{
"value": "note",
"count": 1
}
],
"buttonPatterns": [
{
"value": "content_copy",
"count": 25
},
{
"value": "favorite_border",
"count": 25
},
{
"value": "format_line_spacing",
"count": 1
},
{
"value": "filter_list",
"count": 1
},
{
"value": "add_circle_outline",
"count": 1
},
{
"value": "arrow_drop_down",
"count": 1
},
{
"value": "note_alt",
"count": 1
}
],
"sampleHeadings": [],
"stats": {
"buttons": 55,
"headings": 0
}
}

View file

@ -0,0 +1,175 @@
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {
"color": {
"palette": [
{
"slug": "primary",
"color": "#d08728",
"name": "Primary"
},
{
"slug": "neutral-1",
"color": "#000000",
"name": "Neutral 1"
},
{
"slug": "neutral-2",
"color": "#efefef",
"name": "Neutral 2"
},
{
"slug": "neutral-3",
"color": "#616161",
"name": "Neutral 3"
},
{
"slug": "neutral-4",
"color": "#373737",
"name": "Neutral 4"
},
{
"slug": "neutral-5",
"color": "#171717",
"name": "Neutral 5"
},
{
"slug": "bg-ffffff",
"color": "#ffffff",
"name": "Background #ffffff"
},
{
"slug": "bg-e5e5e5",
"color": "#e5e5e5",
"name": "Background #e5e5e5"
},
{
"slug": "bg-171717",
"color": "#171717",
"name": "Background #171717"
}
],
"gradients": []
},
"typography": {
"fontFamilies": [
{
"fontFamily": "Helvetica",
"slug": "helvetica",
"name": "Helvetica"
},
{
"fontFamily": "Arial",
"slug": "arial",
"name": "Arial"
},
{
"fontFamily": "Times New Roman",
"slug": "times-new-roman",
"name": "Times New Roman"
},
{
"fontFamily": "Inter",
"slug": "inter",
"name": "Inter"
}
],
"fontSizes": [
{
"size": "50px",
"slug": "size-50",
"name": "50px"
},
{
"size": "42px",
"slug": "size-42",
"name": "42px"
},
{
"size": "24px",
"slug": "size-24",
"name": "24px"
},
{
"size": "18px",
"slug": "size-18",
"name": "18px"
},
{
"size": "16px",
"slug": "size-16",
"name": "16px"
},
{
"size": "14px",
"slug": "size-14",
"name": "14px"
},
{
"size": "13.3333px",
"slug": "size-13.3333",
"name": "13.3333px"
}
]
},
"spacing": {
"spacingSizes": [
{
"size": "1px",
"slug": "spacing-1",
"name": "1px"
},
{
"size": "24px",
"slug": "spacing-24",
"name": "24px"
},
{
"size": "32px",
"slug": "spacing-32",
"name": "32px"
},
{
"size": "40px",
"slug": "spacing-40",
"name": "40px"
},
{
"size": "60px",
"slug": "spacing-60",
"name": "60px"
},
{
"size": "80px",
"slug": "spacing-80",
"name": "80px"
},
{
"size": "96px",
"slug": "spacing-96",
"name": "96px"
},
{
"size": "320px",
"slug": "spacing-320",
"name": "320px"
}
]
},
"layout": {
"contentSize": "1200px",
"wideSize": "1400px"
}
},
"styles": {
"color": {
"background": "#ffffff",
"text": "#000000"
},
"typography": {
"fontFamily": "Helvetica"
},
"spacing": {}
}
}

View file

@ -0,0 +1,795 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>coulomb.social · brand guidelines</title>
<meta name="description" content="Design-system documentation for coulomb.social: colour, type, spacing, motion, voice, accessibility, components, and drop-in tokens.">
<meta property="og:title" content="coulomb.social · brand guidelines">
<meta property="og:description" content="Design-system documentation for coulomb.social: colour, type, spacing, motion, voice, accessibility, components, and drop-in tokens.">
<meta property="og:type" content="article">
<meta name="twitter:card" content="summary_large_image">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Instrument%20Serif&family=Inter:wght@400;500;600&family=JetBrains%20Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
:root {
--paper: #f6f3ec;
--paper-2: #efebe1;
--ink: #131313;
--ink-soft: #555048;
--ink-faint: #8a8579;
--rule: #e0dccf;
--accent: #d08728;
--display: 'Instrument Serif', 'Times New Roman', serif;
--body: 'Inter', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
--mono: 'JetBrains Mono', ui-monospace, 'SF Mono', monospace;
}
[data-theme="dark"] {
--paper: #0d0c0a;
--paper-2: #15140f;
--ink: #ece8de;
--ink-soft: #9d978a;
--ink-faint: #5b574e;
--rule: #292621;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
html, body { margin: 0; padding: 0; }
body {
background: var(--paper);
color: var(--ink);
font-family: var(--body);
font-size: 16px;
line-height: 1.6;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
transition: background .25s, color .25s;
}
a { color: var(--ink); text-decoration: none; border-bottom: 1px solid var(--rule); padding-bottom: 1px; }
a:hover { border-color: var(--ink); }
code { font-family: var(--mono); font-size: 0.92em; }
.muted { color: var(--ink-soft); }
.summary { font-family: var(--mono); font-size: 12px; letter-spacing: .04em; color: var(--ink-faint); margin: 0 0 32px; padding-bottom: 14px; border-bottom: 1px solid var(--rule); }
.wrap { max-width: 880px; margin: 0 auto; padding: 0 0 96px; }
/* — Top bar — */
.topbar { display: flex; justify-content: space-between; align-items: center; padding: 24px 40px; font-size: 13px; border-bottom: 1px solid var(--rule); }
.brand { font-family: var(--display); font-size: 22px; }
.brand a { color: var(--ink); text-decoration: none; border-bottom: 0; }
.topbar nav { display: flex; gap: 18px; align-items: center; color: var(--ink-soft); }
.theme-btn { background: transparent; border: 1px solid var(--rule); color: var(--ink-soft); font-size: 11px; padding: 6px 12px; border-radius: 999px; cursor: pointer; letter-spacing: .12em; text-transform: uppercase; font-family: var(--body); }
.theme-btn:hover { color: var(--ink); border-color: var(--ink); }
/* — Cover — */
.cover { padding: 0; border-bottom: 1px solid var(--rule); }
.cover-band {
height: clamp(180px, 28vw, 320px);
display: flex;
align-items: flex-end;
justify-content: space-between;
padding: 32px 40px;
}
.cover-band-label {
font-family: var(--mono);
font-size: 11px;
text-transform: uppercase;
letter-spacing: .18em;
opacity: 0.78;
}
.cover-band-hex code { font-family: var(--mono); font-size: 13px; opacity: 0.9; }
.cover-body { padding: 56px 40px 64px; }
.kicker { font-family: var(--mono); text-transform: uppercase; letter-spacing: .18em; font-size: 11px; color: var(--ink-soft); margin: 0 0 18px; }
.cover-title {
font-family: var(--display);
font-weight: 400;
font-size: clamp(56px, 11vw, 132px);
line-height: .94;
letter-spacing: -.02em;
margin: 0 0 24px;
}
.cover-sub { font-size: 19px; line-height: 1.5; color: var(--ink-soft); max-width: 60ch; margin: 0 0 36px; }
.cover-meta { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 22px 32px; padding: 28px 0 0; border-top: 1px solid var(--rule); margin: 0; }
.cover-meta dt { font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: .14em; color: var(--ink-faint); margin-bottom: 4px; }
.cover-meta dd { margin: 0; font-size: 15px; }
/* — TOC — */
.toc { padding: 56px 40px; border-bottom: 1px solid var(--rule); background: var(--paper-2); }
.toc-title { font-family: var(--display); font-weight: 400; font-size: 28px; margin: 0 0 24px; }
.toc ol { list-style: none; padding: 0; margin: 0; columns: 2; column-gap: 48px; }
@media (max-width: 640px) { .toc ol { columns: 1; } .toc, .topbar, .cover-band, .cover-body { padding-left: 22px; padding-right: 22px; } }
.toc li { padding: 10px 0; border-top: 1px solid var(--rule); break-inside: avoid; }
.toc li:last-child { border-bottom: 1px solid var(--rule); }
.toc a { display: flex; gap: 14px; align-items: baseline; border: 0; }
.toc-num { font-family: var(--mono); font-size: 11px; color: var(--ink-faint); width: 26px; }
.toc-label { font-family: var(--display); font-size: 18px; }
/* — Sections — */
section { padding: 72px 40px; border-bottom: 1px solid var(--rule); }
section:last-of-type { border-bottom: 0; }
@media (max-width: 640px) { section { padding: 48px 22px; } }
.chapter-header { padding-bottom: 18px; margin-bottom: 28px; border-bottom: 1px solid var(--rule); }
.sec-num { font-family: var(--mono); font-size: 11px; letter-spacing: .14em; color: var(--ink-faint); text-transform: uppercase; display: block; margin-bottom: 10px; }
section h2 { font-family: var(--display); font-weight: 400; font-size: clamp(36px, 4.5vw, 56px); line-height: 1.04; letter-spacing: -.005em; margin: 0; }
.sub { font-family: var(--display); font-weight: 400; font-size: 22px; margin: 36px 0 14px; }
/* — Meta grid — */
.meta-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 18px 32px; padding: 0; margin: 0 0 24px; }
.meta-grid > div { padding: 0; }
.meta-grid dt { font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: .12em; color: var(--ink-faint); margin-bottom: 4px; }
.meta-grid dd { margin: 0; font-size: 15px; }
/* — Color section — */
.brand-grid { display: grid; gap: 20px; margin: 0 0 28px; }
.brand-grid-pair { grid-template-columns: 1fr 1fr; }
@media (max-width: 640px) { .brand-grid-pair { grid-template-columns: 1fr; } }
.brand-color { display: flex; flex-direction: column; gap: 14px; }
.big-swatch {
aspect-ratio: 1.9 / 1;
border-radius: 8px;
padding: 22px 24px;
display: flex;
flex-direction: column;
justify-content: space-between;
box-shadow: inset 0 0 0 1px rgba(0,0,0,.06);
}
.brand-color-primary .big-swatch { aspect-ratio: 2.6 / 1; }
.big-swatch-name { font-family: var(--display); font-size: 32px; line-height: 1; }
.big-swatch-hex { font-family: var(--mono); font-size: 14px; letter-spacing: .04em; opacity: 0.92; }
.color-meta { display: grid; grid-template-columns: 1fr 1fr; gap: 0 24px; padding: 0; margin: 0; }
.color-meta dt { font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: .12em; color: var(--ink-faint); margin-bottom: 2px; }
.color-meta dd { margin: 0 0 10px; font-size: 14px; }
.neutral-strip { display: grid; grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); border: 1px solid var(--rule); border-radius: 6px; overflow: hidden; }
.neutral-cell { aspect-ratio: 1.8 / 1; display: flex; align-items: flex-end; padding: 10px 12px; }
.neutral-cell code { font-size: 11px; }
.palette-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); gap: 6px; }
.mini-swatch { aspect-ratio: 1.6 / 1; border-radius: 5px; padding: 9px 11px; display: flex; align-items: flex-end; box-shadow: inset 0 0 0 1px rgba(0,0,0,.06); }
.mini-swatch code { font-size: 10px; opacity: 0.92; }
.callout {
margin-top: 32px;
padding: 14px 18px;
background: rgba(0,0,0,.03);
border-left: 2px solid var(--accent);
border-radius: 0 4px 4px 0;
font-size: 14px;
}
[data-theme="dark"] .callout { background: rgba(255,255,255,.04); }
/* — Logo — */
.logo-card { display: grid; grid-template-columns: 2fr 1fr; gap: 24px; align-items: center; padding: 24px 0; }
@media (max-width: 640px) { .logo-card { grid-template-columns: 1fr; } }
.logo-canvas { aspect-ratio: 16 / 9; background: var(--paper-2); border-radius: 8px; display: flex; align-items: center; justify-content: center; padding: 32px; box-shadow: inset 0 0 0 1px var(--rule); }
.logo-canvas svg { max-width: 60%; max-height: 80%; }
.logo-placeholder { font-family: var(--display); font-size: 36px; color: var(--ink-soft); }
.logo-meta { grid-template-columns: 1fr; }
/* — Type — */
.specimen { padding: 18px 0 26px; }
.spec-line { line-height: 1.05; margin: 0 0 18px; letter-spacing: -.01em; }
.spec-display { font-weight: 400; }
.spec-body { color: var(--ink-soft); font-style: italic; }
.scale-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.scale-table th, .scale-table td { padding: 14px 8px; text-align: left; border-bottom: 1px solid var(--rule); vertical-align: middle; }
.scale-table th { font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: .12em; color: var(--ink-faint); border-bottom: 1px solid var(--ink); }
.scale-table .t-step { width: 64px; }
.scale-table .t-size { width: 80px; }
.scale-table .t-sample { color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* — Spacing — */
.space-rhythm { display: flex; flex-direction: column; gap: 10px; padding: 8px 0; }
.space-step { display: flex; align-items: center; gap: 14px; }
.space-block { height: 14px; background: var(--ink); border-radius: 2px; flex: 0 0 auto; }
[data-theme="dark"] .space-block { background: var(--ink); }
.space-step code { font-size: 11px; color: var(--ink-soft); min-width: 56px; }
/* — Shape — */
.radii-row, .shadows-row { display: grid; gap: 16px; }
.radii-row { grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); }
.shadows-row { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); }
.radius-card, .shadow-card { display: flex; flex-direction: column; gap: 10px; align-items: flex-start; }
.radius-block { width: 96px; height: 96px; background: var(--paper-2); box-shadow: inset 0 0 0 1px var(--rule); }
.shadow-block { width: 100%; height: 96px; background: var(--paper); border-radius: 10px; }
[data-theme="dark"] .shadow-block { background: var(--paper-2); }
.radius-card code, .shadow-card code { font-size: 11px; color: var(--ink-soft); }
/* — Iconography — */
.icon-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(56px, 1fr)); gap: 10px; }
.icon-cell { aspect-ratio: 1; display: flex; align-items: center; justify-content: center; border: 1px solid var(--rule); border-radius: 6px; padding: 10px; background: var(--paper-2); }
.icon-cell svg { width: 100%; height: 100%; }
/* — Motion — */
.motion-tempo { display: flex; flex-direction: column; gap: 10px; }
.tempo-item { display: flex; align-items: center; gap: 14px; }
.tempo-bar { height: 6px; border-radius: 999px; min-width: 24px; opacity: 0.8; flex: 0 0 auto; animation: tempoSlide var(--dur, 600ms) cubic-bezier(.2,.7,.2,1) infinite alternate; }
@keyframes tempoSlide { from { width: 24px; opacity: 0.5; } to { width: 280px; opacity: 0.95; } }
.tempo-item code { font-family: var(--mono); font-size: 12px; color: var(--ink-soft); min-width: 120px; }
.easings { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: 10px; }
.easings li { padding: 6px 12px; background: var(--paper-2); border: 1px solid var(--rule); border-radius: 4px; font-size: 12px; }
/* — Components — */
.mock-grid { display: grid; grid-template-columns: 1fr 1.4fr; gap: 24px; align-items: start; padding: 8px 0 28px; }
@media (max-width: 640px) { .mock-grid { grid-template-columns: 1fr; } }
.mock-button { display: flex; flex-direction: column; gap: 14px; padding: 32px; background: var(--paper-2); border-radius: 12px; box-shadow: inset 0 0 0 1px var(--rule); align-items: flex-start; }
.m-btn { font-family: var(--body); font-size: 14px; font-weight: 500; padding: 12px 22px; border: 1px solid transparent; cursor: pointer; }
.m-btn-secondary { background: transparent; border-style: solid; border-width: 1px; }
.mock-card { padding: 26px 28px; box-shadow: inset 0 0 0 1px var(--rule); }
.m-card-eyebrow { font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: .14em; color: var(--ink-faint); }
.m-card-title { font-family: var(--display); font-weight: 400; font-size: 26px; margin: 8px 0 8px; line-height: 1.1; }
.m-card-body { margin: 0 0 14px; font-size: 14px; color: var(--ink-soft); line-height: 1.5; }
.m-card-link { font-family: var(--body); font-size: 13px; font-weight: 500; border: 0; padding: 0; }
.component-list { display: flex; flex-direction: column; }
.component-card { padding: 18px 0; border-top: 1px solid var(--rule); }
.component-card:last-of-type { border-bottom: 1px solid var(--rule); }
.component-card h4 { font-family: var(--display); font-weight: 400; font-size: 22px; margin: 0 0 14px; }
/* — Voice — */
.quotes { list-style: none; padding: 0; margin: 0; }
.quotes li {
font-family: var(--display);
font-size: 26px;
line-height: 1.18;
padding: 22px 0;
border-top: 1px solid var(--rule);
color: var(--ink);
}
.quotes li:last-child { border-bottom: 1px solid var(--rule); }
.cta-verbs { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: 8px 20px; }
.cta-verbs li { display: flex; align-items: baseline; gap: 6px; font-size: 14px; }
.cta-verbs code { font-size: 13px; }
.cta-verbs .muted { font-family: var(--mono); font-size: 11px; }
/* — Accessibility — */
.a11y-score { display: flex; align-items: baseline; gap: 24px; padding: 12px 0 32px; border-bottom: 1px solid var(--rule); margin-bottom: 24px; }
.a11y-num { font-family: var(--display); font-size: clamp(72px, 10vw, 120px); line-height: 1; letter-spacing: -.02em; }
.a11y-suffix { font-size: 0.5em; color: var(--ink-soft); margin-left: 4px; }
.a11y-label { color: var(--ink-soft); font-size: 14px; line-height: 1.4; }
.a11y-pairs { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 18px; }
.a11y-pair { display: flex; flex-direction: column; gap: 12px; }
.a11y-stack { padding: 22px 18px; border-radius: 6px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.06); display: flex; justify-content: space-between; align-items: center; }
.a11y-Aa { font-family: var(--display); font-size: 32px; line-height: 1; }
.a11y-ratio { font-family: var(--mono); font-size: 12px; opacity: 0.9; }
.a11y-pair dl { display: grid; grid-template-columns: 1fr 1fr; gap: 0 12px; padding: 0; margin: 0; }
.a11y-pair dt { font-family: var(--mono); font-size: 9px; text-transform: uppercase; letter-spacing: .14em; color: var(--ink-faint); }
.a11y-pair dd { margin: 0 0 4px; font-size: 12px; }
.remediation { list-style: none; padding: 0; margin: 0; }
.remediation li { padding: 10px 0; border-top: 1px solid var(--rule); }
.remediation li:last-child { border-bottom: 1px solid var(--rule); }
/* — Tokens — */
.codeblock-wrap { margin: 0 0 18px; border: 1px solid var(--rule); border-radius: 6px; overflow: hidden; }
.codeblock-head { display: flex; justify-content: space-between; padding: 10px 14px; font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: .14em; color: var(--ink-faint); background: var(--paper-2); border-bottom: 1px solid var(--rule); }
.codeblock { background: var(--paper-2); padding: 16px 18px; overflow-x: auto; font-family: var(--mono); font-size: 12px; line-height: 1.6; margin: 0; color: var(--ink); }
/* — Usage — */
.usage-list { padding: 0; margin: 0; counter-reset: rule; list-style: none; }
.usage-list li { padding: 22px 0; border-top: 1px solid var(--rule); position: relative; padding-left: 56px; counter-increment: rule; }
.usage-list li:last-child { border-bottom: 1px solid var(--rule); }
.usage-list li::before { content: counter(rule, decimal-leading-zero); position: absolute; left: 0; top: 26px; font-family: var(--mono); font-size: 11px; color: var(--ink-faint); letter-spacing: .14em; }
.usage-title { font-family: var(--display); font-weight: 400; font-size: 22px; margin: 0 0 6px; }
.usage-body { margin: 0; color: var(--ink-soft); font-size: 15px; line-height: 1.55; }
/* — Footer — */
footer { padding: 40px 40px 0; font-size: 13px; color: var(--ink-soft); display: flex; justify-content: space-between; align-items: end; flex-wrap: wrap; gap: 16px; }
footer .sig { font-family: var(--display); font-size: 22px; color: var(--ink); }
footer .stamp { font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: .14em; }
@media (max-width: 640px) { footer { padding: 40px 22px 0; } }
/* — Print — */
@media print {
body { background: white; color: black; }
.topbar nav, .theme-btn { display: none; }
.cover, .toc, section { page-break-inside: avoid; border-color: #ddd; padding: 36px 32px; }
.cover-band { background-color: var(--accent) !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.toc, .cover { page-break-after: always; }
section { page-break-before: always; page-break-after: always; break-before: page; }
.topbar { display: none !important; }
.scale-table, .a11y-pair, .component-card { page-break-inside: avoid; }
}
</style>
</head>
<body>
<header class="topbar">
<div class="brand"><a href="https://designlang.app">designlang</a></div>
<nav>
<span>Brand guidelines</span>
<button class="theme-btn" id="themeBtn" type="button">Theme</button>
</nav>
</header>
<main class="wrap">
<section class="cover" id="cover" aria-labelledby="cover-title">
<div class="cover-band" style="background:#d08728;color:#ffffff">
<span class="cover-band-label">Brand guidelines</span>
<span class="cover-band-hex"><code>#d08728</code></span>
</div>
<div class="cover-body">
<p class="kicker">August 9, 2026</p>
<h1 id="cover-title" class="cover-title">coulomb.social</h1>
<p class="cover-sub">A reading of the visual language at <a href="https://coulomb.social" target="_blank" rel="noopener">https://coulomb.social</a>. Every token, every rule, every component — captured from the live site.</p>
<dl class="cover-meta">
<div><dt>Page intent</dt><dd>landing</dd></div>
<div><dt>System grade</dt><dd>B <span class="muted">85/100</span></dd></div>
<div><dt>Tokens</dt><dd>8 colours · 7 sizes</dd></div>
<div><dt>Generated</dt><dd>designlang</dd></div>
</dl>
</div>
</section>
<nav class="toc" aria-label="Table of contents">
<h2 class="toc-title">Contents</h2>
<ol>
<li><a href="#about"><span class="toc-num">01</span><span class="toc-label">About</span></a></li><li><a href="#logo"><span class="toc-num">02</span><span class="toc-label">Logo</span></a></li><li><a href="#color"><span class="toc-num">03</span><span class="toc-label">Colour</span></a></li><li><a href="#type"><span class="toc-num">04</span><span class="toc-label">Typography</span></a></li><li><a href="#spacing"><span class="toc-num">05</span><span class="toc-label">Spacing</span></a></li><li><a href="#shape"><span class="toc-num">06</span><span class="toc-label">Shape</span></a></li><li><a href="#iconography"><span class="toc-num">07</span><span class="toc-label">Iconography</span></a></li><li><a href="#motion"><span class="toc-num">08</span><span class="toc-label">Motion</span></a></li><li><a href="#components"><span class="toc-num">09</span><span class="toc-label">Components</span></a></li><li><a href="#voice"><span class="toc-num">10</span><span class="toc-label">Voice</span></a></li><li><a href="#accessibility"><span class="toc-num">11</span><span class="toc-label">Accessibility</span></a></li><li><a href="#tokens"><span class="toc-num">12</span><span class="toc-label">Tokens</span></a></li><li><a href="#usage"><span class="toc-num">13</span><span class="toc-label">Usage</span></a></li>
</ol>
</nav>
<section id="about">
<header class="chapter-header">
<span class="sec-num">Chapter 01</span>
<h2>About</h2>
</header>
<dl class="meta-grid">
<div><dt>Page intent</dt><dd>landing <span class="muted">45% confidence</span></dd></div>
<div><dt>Material language</dt><dd>flat</dd></div>
<div><dt>Imagery style</dt><dd>mixed</dd></div>
<div><dt>Component library</dt><dd>unknown</dd></div>
<div><dt>Stack</dt><dd>unknown · Tailwind</dd></div>
<div><dt>Voice tone</dt><dd>neutral</dd></div>
</dl>
</section>
<section id="logo">
<header class="chapter-header">
<span class="sec-num">Chapter 02</span>
<h2>Logo</h2>
</header>
<div class="logo-card">
<div class="logo-canvas" aria-label="Extracted logo on canvas">
<span class="logo-placeholder">coulomb.social</span>
</div>
<dl class="meta-grid logo-meta">
<div><dt>Source</dt><dd>inferred</dd></div>
<div><dt>Dimensions</dt><dd></dd></div>
<div><dt>Aspect</dt><dd></dd></div>
<div><dt>Format</dt><dd>unknown</dd></div>
</dl>
</div>
</section>
<section id="color">
<header class="chapter-header">
<span class="sec-num">Chapter 03</span>
<h2>Colour</h2>
</header>
<p class="summary">1 primary · 7 neutrals · 8 total</p>
<div class="brand-grid brand-grid-primary">
<article class="brand-color brand-color-primary">
<div class="big-swatch" style="background:#d08728;color:#ffffff">
<span class="big-swatch-name">Primary</span>
<span class="big-swatch-hex">#D08728</span>
</div>
<dl class="color-meta">
<div><dt>RGB</dt><dd><code>208, 135, 40</code></dd></div>
<div><dt>HSL</dt><dd><code>34°, 68%, 49%</code></dd></div>
</dl>
</article></div>
<h3 class="sub">Neutrals</h3>
<div class="neutral-strip">
<div class="neutral-cell" style="background:#000000;color:#ffffff"><code>#000000</code></div><div class="neutral-cell" style="background:#efefef;color:#0a0a0a"><code>#EFEFEF</code></div><div class="neutral-cell" style="background:#616161;color:#ffffff"><code>#616161</code></div><div class="neutral-cell" style="background:#373737;color:#ffffff"><code>#373737</code></div><div class="neutral-cell" style="background:#171717;color:#ffffff"><code>#171717</code></div><div class="neutral-cell" style="background:#ffffff;color:#0a0a0a"><code>#FFFFFF</code></div><div class="neutral-cell" style="background:#e5e5e5;color:#0a0a0a"><code>#E5E5E5</code></div>
</div>
<h3 class="sub">Full palette</h3>
<div class="palette-grid">
<div class="mini-swatch" style="background:#000000;color:#ffffff"><code>#000000</code></div><div class="mini-swatch" style="background:#efefef;color:#0a0a0a"><code>#EFEFEF</code></div><div class="mini-swatch" style="background:#616161;color:#ffffff"><code>#616161</code></div><div class="mini-swatch" style="background:#373737;color:#ffffff"><code>#373737</code></div><div class="mini-swatch" style="background:#171717;color:#ffffff"><code>#171717</code></div><div class="mini-swatch" style="background:#ffffff;color:#0a0a0a"><code>#FFFFFF</code></div><div class="mini-swatch" style="background:#e5e5e5;color:#0a0a0a"><code>#E5E5E5</code></div><div class="mini-swatch" style="background:#d08728;color:#ffffff"><code>#D08728</code></div>
</div>
<p class="callout"><strong>WCAG 100%</strong> · 0 passing pairs · 0 failing. Full breakdown in §11.</p>
</section>
<section id="type">
<header class="chapter-header">
<span class="sec-num">Chapter 04</span>
<h2>Typography</h2>
</header>
<p class="summary">4 families · 7 sizes · 4 weights</p>
<dl class="meta-grid">
<div><dt>Display</dt><dd>Helvetica</dd></div>
<div><dt>Body</dt><dd>Arial</dd></div>
<div><dt>Weights</dt><dd>400, 500, 600, 700</dd></div>
</dl>
<h3 class="sub">Specimen</h3>
<div class="specimen" style="font-family: Helvetica, 'Instrument Serif', serif;">
<div class="spec-line spec-display" style="font-size: 50px">Quick brown fox jumps over the lazy dog.</div>
<div class="spec-line spec-body" style="font-size: 24px">AaBbCc 0123456789 ?!&amp;</div>
</div>
<h3 class="sub">Scale</h3>
<table class="scale-table">
<thead><tr><th class="t-step">Step</th><th class="t-size">Size</th><th class="t-sample">Sample</th></tr></thead>
<tbody>
<tr>
<td class="t-step"><code>t00</code></td>
<td class="t-size"><code>50px</code></td>
<td class="t-sample" style="font-size:50px; font-family: Helvetica, 'Instrument Serif', serif; line-height: 1;">Quick brown fox jumps over t</td>
</tr>
<tr>
<td class="t-step"><code>t01</code></td>
<td class="t-size"><code>42px</code></td>
<td class="t-sample" style="font-size:42px; font-family: Helvetica, 'Instrument Serif', serif; line-height: 1;">Quick brown fox jumps over t</td>
</tr>
<tr>
<td class="t-step"><code>t02</code></td>
<td class="t-size"><code>24px</code></td>
<td class="t-sample" style="font-size:24px; font-family: Helvetica, 'Instrument Serif', serif; line-height: 1;">Quick brown fox jumps over t</td>
</tr>
<tr>
<td class="t-step"><code>t03</code></td>
<td class="t-size"><code>18px</code></td>
<td class="t-sample" style="font-size:18px; font-family: Helvetica, 'Instrument Serif', serif; line-height: 1;">Quick brown fox jumps over t</td>
</tr>
<tr>
<td class="t-step"><code>t04</code></td>
<td class="t-size"><code>16px</code></td>
<td class="t-sample" style="font-size:16px; font-family: Helvetica, 'Instrument Serif', serif; line-height: 1;">Quick brown fox jumps over t</td>
</tr>
<tr>
<td class="t-step"><code>t05</code></td>
<td class="t-size"><code>14px</code></td>
<td class="t-sample" style="font-size:14px; font-family: Helvetica, 'Instrument Serif', serif; line-height: 1;">Quick brown fox jumps over t</td>
</tr>
<tr>
<td class="t-step"><code>t06</code></td>
<td class="t-size"><code>13.3333px</code></td>
<td class="t-sample" style="font-size:13.3333px; font-family: Helvetica, 'Instrument Serif', serif; line-height: 1;">Quick brown fox jumps over t</td>
</tr>
</tbody>
</table>
</section>
<section id="spacing">
<header class="chapter-header">
<span class="sec-num">Chapter 05</span>
<h2>Spacing</h2>
</header>
<p class="summary">Base 4px · 8 steps captured</p>
<h3 class="sub">Rhythm</h3>
<div class="space-rhythm">
<div class="space-step">
<div class="space-block" style="width:1.6px"></div>
<code>1px</code>
</div>
<div class="space-step">
<div class="space-block" style="width:38.400000000000006px"></div>
<code>24px</code>
</div>
<div class="space-step">
<div class="space-block" style="width:51.2px"></div>
<code>32px</code>
</div>
<div class="space-step">
<div class="space-block" style="width:64px"></div>
<code>40px</code>
</div>
<div class="space-step">
<div class="space-block" style="width:96px"></div>
<code>60px</code>
</div>
<div class="space-step">
<div class="space-block" style="width:128px"></div>
<code>80px</code>
</div>
<div class="space-step">
<div class="space-block" style="width:153.60000000000002px"></div>
<code>96px</code>
</div>
<div class="space-step">
<div class="space-block" style="width:320px"></div>
<code>320px</code>
</div>
</div>
</section>
<section id="shape">
<header class="chapter-header">
<span class="sec-num">Chapter 06</span>
<h2>Shape</h2>
</header>
<p class="summary">5 radii · 2 elevation tiers</p>
<h3 class="sub">Border radii</h3>
<div class="radii-row">
<div class="radius-card">
<div class="radius-block" style="border-radius:4px"></div>
<code>4px</code>
</div>
<div class="radius-card">
<div class="radius-block" style="border-radius:8px"></div>
<code>8px</code>
</div>
<div class="radius-card">
<div class="radius-block" style="border-radius:12px"></div>
<code>12px</code>
</div>
<div class="radius-card">
<div class="radius-block" style="border-radius:15px"></div>
<code>15px</code>
</div>
<div class="radius-card">
<div class="radius-block" style="border-radius:20px"></div>
<code>20px</code>
</div>
</div>
<h3 class="sub">Elevation</h3>
<div class="shadows-row">
<div class="shadow-card">
<div class="shadow-block" style="box-shadow:rgb(170, 170, 170) 2px 2px 4px 0px"></div>
<code>xs</code>
</div>
<div class="shadow-card">
<div class="shadow-block" style="box-shadow:rgba(23, 23, 23, 0.1) 2px 2px 8px 2px"></div>
<code>sm</code>
</div>
</div>
</section>
<section id="iconography">
<header class="chapter-header">
<span class="sec-num">Chapter 07</span>
<h2>Iconography</h2>
</header>
<p class="summary">unknown · 24 captured</p>
<dl class="meta-grid">
<div><dt>Library</dt><dd>unknown</dd></div>
<div><dt>Confidence</dt><dd>0%</dd></div>
<div><dt>Stroke style</dt><dd>fillDominant</dd></div>
</dl>
<div class="icon-grid">
<div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div><div class="icon-cell"><code>icon</code></div>
</div>
</section>
<section id="motion">
<header class="chapter-header">
<span class="sec-num">Chapter 08</span>
<h2>Motion</h2>
</header>
<p class="summary">Feel: mixed · 1 durations · 0 easings</p>
<h3 class="sub">Duration scale</h3>
<div class="motion-tempo">
<div class="tempo-item">
<div class="tempo-bar" style="--dur:250ms; background:#d08728"></div>
<code>250ms</code>
</div>
</div>
</section>
<section id="components">
<header class="chapter-header">
<span class="sec-num">Chapter 09</span>
<h2>Components</h2>
</header>
<p class="summary">unknown · 1 component patterns captured</p>
<h3 class="sub">Mocks</h3>
<div class="mock-grid">
<div class="mock-button">
<button type="button" class="m-btn m-btn-primary" style="background:#d08728;color:#ffffff;border-radius:8px">Primary action</button>
<button type="button" class="m-btn m-btn-secondary" style="border-radius:8px;border-color:#d08728;color:#d08728">Secondary</button>
</div>
<div class="mock-card" style="background:#e5e5e5;color:#000000;border-radius:12px">
<span class="m-card-eyebrow">Card</span>
<h4 class="m-card-title">Built from these tokens</h4>
<p class="m-card-body">Radius, primary, surface, text — all sampled from the live site.</p>
<a class="m-card-link" href="#" style="color:#d08728">Read more →</a>
</div>
</div>
<h3 class="sub">Detected patterns</h3>
<div class="component-list">
<article class="component-card">
<h4>button</h4>
<dl class="meta-grid">
<div><dt>Slots</dt><dd>label, icon, badge</dd></div>
<div><dt>Variants</dt><dd></dd></div>
<div><dt>Sizes</dt><dd></dd></div>
</dl>
</article>
</div>
</section>
<section id="voice">
<header class="chapter-header">
<span class="sec-num">Chapter 10</span>
<h2>Voice</h2>
</header>
<p class="summary">neutral · — · —</p>
<h3 class="sub">CTA verbs</h3>
<ul class="cta-verbs">
<li><code></code><span class="muted">×25</span></li><li><code></code><span class="muted">×25</span></li><li><code></code><span class="muted">×1</span></li><li><code></code><span class="muted">×1</span></li><li><code></code><span class="muted">×1</span></li><li><code></code><span class="muted">×1</span></li><li><code></code><span class="muted">×1</span></li>
</ul>
</section>
<section id="accessibility">
<header class="chapter-header">
<span class="sec-num">Chapter 11</span>
<h2>Accessibility</h2>
</header>
<div class="a11y-score">
<span class="a11y-num">100<span class="a11y-suffix">%</span></span>
<span class="a11y-label">WCAG 2.1 contrast<br>0 passing · 0 failing</span>
</div>
<p class="muted">No failing contrast pairs detected.</p>
</section>
<section id="tokens">
<header class="chapter-header">
<span class="sec-num">Chapter 12</span>
<h2>Tokens</h2>
</header>
<p class="summary">Drop-in code for the most common stacks. All values from the live extraction.</p>
<div class="codeblock-wrap">
<div class="codeblock-head"><span>CSS variables</span><span class="muted">variables.css</span></div>
<pre class="codeblock"><code>:root {
--color-primary: #d08728;
--font-display: &quot;Helvetica&quot;;
--space-base: 4px;
--radius-md: 8px;
}</code></pre>
</div>
<div class="codeblock-wrap">
<div class="codeblock-head"><span>Tailwind config</span><span class="muted">tailwind.config.js</span></div>
<pre class="codeblock"><code>// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: { brand: &#39;#d08728&#39; },
fontFamily: { display: [&#39;Helvetica&#39;, &#39;serif&#39;] },
spacing: { base: &#39;4px&#39; },
borderRadius: { md: &#39;8px&#39; },
},
},
};</code></pre>
</div>
<p class="muted">Run <code>npx designlang pack coulomb.social</code> for the full bundle (DTCG, shadcn, Figma vars, motion, anatomy, Storybook).</p>
</section>
<section id="usage">
<header class="chapter-header">
<span class="sec-num">Chapter 13</span>
<h2>Usage</h2>
</header>
<ol class="usage-list">
<li>
<h3 class="usage-title">Lead with the primary.</h3>
<p class="usage-body">It belongs on calls-to-action and one accent moment per screen. Not on body copy.</p>
</li>
<li>
<h3 class="usage-title">Two type families, three weights.</h3>
<p class="usage-body">Display for headlines, body for paragraphs. Resist a third unless there is a real reason.</p>
</li>
<li>
<h3 class="usage-title">Snap to the spacing scale.</h3>
<p class="usage-body">Padding, margin, and gap should land on the values in §05. One-off pixels accumulate into noise.</p>
</li>
<li>
<h3 class="usage-title">Treat accessibility as a hard constraint.</h3>
<p class="usage-body">When a colour pair fails WCAG, fix the colour — not the contrast check.</p>
</li>
</ol>
</section>
<footer>
<div>
<div class="sig">designlang</div>
<div>Re-run: <code>npx designlang brand coulomb.social</code></div>
</div>
<div class="stamp">Aug 9, 2026 · v12.21.0</div>
</footer>
</main>
<script>
(function () {
var btn = document.getElementById('themeBtn');
var saved = null;
try { saved = localStorage.getItem('dl-theme'); } catch (e) {}
if (saved) document.documentElement.setAttribute('data-theme', saved);
btn && btn.addEventListener('click', function () {
var cur = document.documentElement.getAttribute('data-theme') === 'dark' ? '' : 'dark';
if (cur) document.documentElement.setAttribute('data-theme', cur);
else document.documentElement.removeAttribute('data-theme');
try { localStorage.setItem('dl-theme', cur); } catch (e) {}
});
})();
</script>
</body>
</html>

View file

@ -1,120 +0,0 @@
# Prompt pack
Paste-ready prompts for coulomb.social. Use the variant that matches your tool.
## v0.txt
```
Build a landing page with this exact visual language.
COLORS:
#000000
#171717
#d08728
#ffffff
#616161
#e5e5e5
FONTS: [object Object], [object Object], [object Object], [object Object]
SPACING: 2, 32, 68
RADIUS: 4, 8
SHADOWS: rgb(97, 97, 97) 2px 2px 8px 0px
MATERIAL LANGUAGE: flat
VOICE: Tone: neutral · Headings: unknown
SECTIONS (in order):
- hero
- features
- cta
- footer
Use Tailwind. Match these tokens exactly. Keep the material language consistent.
```
## lovable.txt
```
Clone the design language of this landing page and build a fresh equivalent.
Visual feel: flat. Tone: neutral · Headings: unknown
Primary palette: #000000, #171717, #d08728, #ffffff, #616161.
Typography: [object Object], [object Object], [object Object], [object Object].
Corner radius vocabulary: 4, 8.
Shadow vocabulary: rgb(97, 97, 97) 2px 2px 8px 0px.
Page structure:
- hero
- features
- social proof
- cta
- footer
```
## cursor.md
```
# Design brief
Page type: **landing**.
Material language: **flat**.
Voice: Tone: neutral · Headings: unknown.
## Tokens
```ts
export const tokens = {
colors: ['#000000', '#171717', '#d08728', '#ffffff', '#616161', '#e5e5e5'],
fonts: ['[object Object]', '[object Object]', '[object Object]', '[object Object]'],
radii: ['4', '8'],
shadows: ['rgb(97, 97, 97) 2px 2px 8px 0px'],
};
```
## Sections
- hero
- features
- cta
- footer
```
## claude-artifacts.md
```
Create a React artifact that reproduces this brand's design language.
Page intent: landing.
Material language: flat.
Voice: Tone: neutral · Headings: unknown.
Colors to use: #000000, #171717, #d08728, #ffffff, #616161, #e5e5e5.
Fonts: [object Object], [object Object], [object Object], [object Object].
Radius vocabulary: 4, 8.
Sections:
- hero
- features
- cta
- footer
Use Tailwind via CDN, lucide-react for icons, and keep the material language consistent across sections. Do not add extra decorative elements outside this vocabulary.
```
## Recipes
### button
# Recipe: button
Build one button component that matches this brand.
Palette: #000000, #171717, #d08728, #ffffff, #616161, #e5e5e5
Typography: [object Object], [object Object], [object Object], [object Object]
Material: flat
Signals: Radius: 4, 8 · Shadows: rgb(97, 97, 97) 2px 2px 8px 0px
## Anatomy (detected)
```json
{
"kind": "button",
"structuralHash": "button>svg",
"instanceCount": 1,
"variants": [
{
"css": {
"background": "rgba(0, 0, 0, 0)",
"color": "rgb(208, 135, 40)",
"padding": "5px 5px 5px 5px",
"borderRadius": "4px",
"border": "0px none rgb(208, 135, 40)",
"fontSize": "13.3333px",
"fontWeight": "400"
},
"instanceCount": 1
}
]
}
```

View file

@ -1,13 +0,0 @@
{
"tone": "neutral",
"pronoun": "third-person",
"headingStyle": "unknown",
"headingLengthClass": "tight",
"ctaVerbs": [],
"buttonPatterns": [],
"sampleHeadings": [],
"stats": {
"buttons": 0,
"headings": 0
}
}

View file

@ -1,18 +0,0 @@
# Design brief
Page type: **landing**.
Material language: **flat**.
Voice: Tone: neutral · Headings: unknown.
## Tokens
```ts
export const tokens = {
colors: ['#000000', '#171717', '#d08728', '#ffffff', '#616161', '#e5e5e5'],
fonts: ['[object Object]', '[object Object]', '[object Object]', '[object Object]'],
radii: ['4', '8'],
shadows: ['rgb(97, 97, 97) 2px 2px 8px 0px'],
};
```
## Sections
- hero
- features
- cta
- footer

View file

@ -1,12 +0,0 @@
Clone the design language of this landing page and build a fresh equivalent.
Visual feel: flat. Tone: neutral · Headings: unknown
Primary palette: #000000, #171717, #d08728, #ffffff, #616161.
Typography: [object Object], [object Object], [object Object], [object Object].
Corner radius vocabulary: 4, 8.
Shadow vocabulary: rgb(97, 97, 97) 2px 2px 8px 0px.
Page structure:
- hero
- features
- social proof
- cta
- footer

View file

@ -1,28 +0,0 @@
# Recipe: button
Build one button component that matches this brand.
Palette: #000000, #171717, #d08728, #ffffff, #616161, #e5e5e5
Typography: [object Object], [object Object], [object Object], [object Object]
Material: flat
Signals: Radius: 4, 8 · Shadows: rgb(97, 97, 97) 2px 2px 8px 0px
## Anatomy (detected)
```json
{
"kind": "button",
"structuralHash": "button>svg",
"instanceCount": 1,
"variants": [
{
"css": {
"background": "rgba(0, 0, 0, 0)",
"color": "rgb(208, 135, 40)",
"padding": "5px 5px 5px 5px",
"borderRadius": "4px",
"border": "0px none rgb(208, 135, 40)",
"fontSize": "13.3333px",
"fontWeight": "400"
},
"instanceCount": 1
}
]
}
```

View file

@ -1,41 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>coulomb.social starter</title>
<link rel="stylesheet" href="../tokens/variables.css">
<style>
body {
margin: 0;
font-family: "Times New Roman", -apple-system, BlinkMacSystemFont, sans-serif;
background: var(--color-background, #fff);
color: var(--color-text, #111);
line-height: 1.5;
}
main { max-width: 840px; margin: 0 auto; padding: 64px 32px; }
h1 { font-size: clamp(40px, 6vw, 72px); line-height: 1.05; margin: 0 0 18px; }
p { font-size: 18px; max-width: 56ch; color: var(--color-text-secondary, #555); }
.cta {
display: inline-block;
padding: 14px 28px;
margin-top: 28px;
background: var(--color-primary, #0a0a0a);
color: var(--color-on-primary, #fff);
border-radius: var(--radius-md, 8px);
text-decoration: none;
font-weight: 600;
}
.cta:hover { opacity: 0.9; }
.meta { margin-top: 64px; font-size: 12px; color: #888; }
.meta a { color: inherit; }
</style>
</head>
<body>
<main>
<h1>Built from coulomb.social</h1>
<p>This starter is wired to the tokens in <code>tokens/variables.css</code>. Edit the variables and watch this page change. Drop in your own components and use the same tokens to keep the visual language consistent.</p>
<a class="cta" href="#">Get started</a>
<p class="meta">Generated by <a href="https://designlang.app">designlang</a>. Re-pack with <code>npx designlang pack coulomb.social</code>.</p>
</main>
</body>
</html>

View file

@ -1,8 +0,0 @@
import type { StorybookConfig } from '@storybook/react-vite';
const config: StorybookConfig = {
stories: ['../stories/**/*.mdx', '../stories/**/*.stories.@(ts|tsx)'],
addons: ['@storybook/addon-essentials', '@storybook/addon-docs'],
framework: { name: '@storybook/react-vite', options: {} },
};
export default config;

View file

@ -1,10 +0,0 @@
import type { Preview } from '@storybook/react';
import './../stories/tokens.css';
const preview: Preview = {
parameters: {
backgrounds: { default: 'paper' },
controls: { matchers: { color: /(background|color)$/i } },
},
};
export default preview;

View file

@ -1,15 +0,0 @@
# Index | Coulomb · Storybook
Auto-generated by `designlang <url> --storybook`.
## Stories
_No anatomy detected on the source page._
## Run
```
npm install
npm run storybook
```
Opens at http://localhost:6006.

View file

@ -1,26 +0,0 @@
{
"name": "index---coulomb-storybook",
"private": true,
"version": "0.1.0",
"type": "module",
"scripts": {
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build"
},
"dependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@storybook/addon-essentials": "^8.0.0",
"@storybook/addon-docs": "^8.0.0",
"@storybook/blocks": "^8.0.0",
"@storybook/react": "^8.0.0",
"@storybook/react-vite": "^8.0.0",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"storybook": "^8.0.0",
"typescript": "^5.0.0",
"vite": "^5.0.0"
}
}

View file

@ -1,15 +0,0 @@
import { Meta, ColorPalette, ColorItem, Typeset } from '@storybook/blocks';
<Meta title="Extracted/Tokens" />
# Design tokens
Extracted from https://coulomb.social by [designlang](https://github.com/Manavarya09/design-extract).
<ColorPalette>
<ColorItem title="primary" colors={{ primary: '#d08728' }} />
<ColorItem title="secondary" colors={{ secondary: '#8b5cf6' }} />
<ColorItem title="accent" colors={{ accent: '#f59e0b' }} />
<ColorItem title="background" colors={{ background: '#ffffff' }} />
<ColorItem title="foreground" colors={{ foreground: '#000000' }} />
</ColorPalette>

View file

@ -1,11 +0,0 @@
:root {
--color-primary: #d08728;
--color-secondary: #8b5cf6;
--color-accent: #f59e0b;
--color-background: #ffffff;
--color-foreground: #000000;
--radius: 8px;
--shadow: rgb(97, 97, 97) 2px 2px 8px 0px;
--font-sans: 'Times New Roman', system-ui, sans-serif;
}
body { background: var(--color-background); color: var(--color-foreground); font-family: var(--font-sans); }

View file

@ -1,15 +0,0 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "Bundler",
"jsx": "react-jsx",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
},
"include": [
"stories/**/*",
".storybook/**/*"
]
}

View file

@ -1,127 +0,0 @@
{
"color": {
"primary": {
"$value": "#d08728",
"$type": "color"
},
"neutral-0": {
"$value": "#000000",
"$type": "color"
},
"neutral-1": {
"$value": "#171717",
"$type": "color"
},
"neutral-2": {
"$value": "#ffffff",
"$type": "color"
},
"neutral-3": {
"$value": "#616161",
"$type": "color"
},
"neutral-4": {
"$value": "#e5e5e5",
"$type": "color"
},
"background-0": {
"$value": "#ffffff",
"$type": "color"
},
"background-1": {
"$value": "#616161",
"$type": "color"
},
"text-0": {
"$value": "#000000",
"$type": "color"
},
"text-1": {
"$value": "#ffffff",
"$type": "color"
},
"text-2": {
"$value": "#171717",
"$type": "color"
},
"text-3": {
"$value": "#d08728",
"$type": "color"
}
},
"fontFamily": {
"body": {
"$value": "Arial",
"$type": "fontFamily"
},
"inter": {
"$value": "Inter",
"$type": "fontFamily"
}
},
"fontSize": {
"8": {
"$value": "8px",
"$type": "dimension"
},
"12": {
"$value": "12px",
"$type": "dimension"
},
"14": {
"$value": "14px",
"$type": "dimension"
},
"16": {
"$value": "16px",
"$type": "dimension"
},
"18": {
"$value": "18px",
"$type": "dimension"
},
"32": {
"$value": "32px",
"$type": "dimension"
},
"48": {
"$value": "48px",
"$type": "dimension"
},
"13.3333": {
"$value": "13.3333px",
"$type": "dimension"
}
},
"spacing": {
"1": {
"$value": "2px",
"$type": "dimension"
},
"16": {
"$value": "32px",
"$type": "dimension"
},
"34": {
"$value": "68px",
"$type": "dimension"
}
},
"borderRadius": {
"sm": {
"$value": "4px",
"$type": "dimension"
},
"md": {
"$value": "8px",
"$type": "dimension"
}
},
"shadow": {
"md": {
"$value": "rgb(97, 97, 97) 2px 2px 8px 0px",
"$type": "shadow"
}
},
"breakpoint": {}
}

View file

@ -142,39 +142,33 @@ async function main() {
const lsKeys = (state.origins || []).flatMap((o) =>
(o.localStorage || []).map((e) => e.name),
);
// Bubble always sets coulomb_* session cookies for anonymous visitors.
// A real login usually adds more localStorage keys and/or more cookies.
const onlyDefaultBubbleCookies =
cookieCount <= 3 &&
(state.cookies || []).every((c) =>
String(c.name || "").startsWith("coulomb_"),
);
const thinLocalStorage =
lsKeys.length === 0 ||
(lsKeys.length === 1 && lsKeys[0] === "algoliasearch-client-js");
if (onlyDefaultBubbleCookies && thinLocalStorage) {
// Bubble often keeps the same coulomb_* cookie *names* for guests and
// members — names alone are not a login signal. Probe the live page:
// authenticated app usually leaves the bare landing path.
let probeUrl = page.url();
let probeTitle = await page.title().catch(() => "");
const path = (() => {
try {
return new URL(probeUrl).pathname;
} catch {
return "";
}
})();
const looksLikeLanding = path === "/" || path === "";
if (looksLikeLanding && !fromPasswordFiles) {
console.error("");
console.error(
"WARNING: This looks like an anonymous Bubble session, not a logged-in user.",
"WARNING: Still on the site root after capture — login may not have completed.",
);
console.error(` url: ${probeUrl}`);
console.error(` title: ${probeTitle}`);
console.error(
` cookies=${cookieCount} (only default coulomb_* names)`,
"Log in fully, open an app page (e.g. Research / Pages), then press Enter.",
);
console.error(` localStorage keys: ${lsKeys.join(", ") || "(none)"}`);
console.error("");
console.error("Do not use this for authenticated design extract.");
console.error("Re-run, fully log in, wait until the app UI is loaded,");
console.error("then press Enter. If login uses a popup, complete it first.");
process.exitCode = 2;
// Still write so you can inspect, but mark filename
const weakPath = STATE_PATH.replace(/\.json$/, ".anonymous.json");
writeFileSync(weakPath, JSON.stringify(state, null, 2) + "\n", {
mode: 0o600,
});
chmodSync(weakPath, 0o600);
console.error(`Wrote weak session for inspection only: ${weakPath}`);
return;
// Continue to save anyway — Bubble guest+member share cookie names; user
// may still have a valid session that only reveals itself after navigation.
}
writeFileSync(STATE_PATH, JSON.stringify(state, null, 2) + "\n", {
@ -186,6 +180,7 @@ async function main() {
console.log(
`Saved storageState (${cookieCount} cookies, ${originCount} origins, localStorage keys: ${lsKeys.length}).`,
);
console.log(` page at save: ${probeUrl}${probeTitle}`);
console.log(`File: ${STATE_PATH}`);
console.log("Next: ./scripts/run-design-extract.sh");
} finally {

21
scripts/probe-auth-session.mjs Executable file
View file

@ -0,0 +1,21 @@
#!/usr/bin/env node
/** Print final URL after loading coulomb.social with storageState (no secrets). */
import { chromium } from "playwright";
import { homedir } from "os";
import { join } from "path";
const statePath =
process.env.COULOMB_SOCIAL_STORAGE_STATE ||
join(homedir(), ".config/coulomb-social/auth/storage-state.json");
const url = process.env.COULOMB_SOCIAL_URL || "https://coulomb.social";
const browser = await chromium.launch({ headless: true });
try {
const context = await browser.newContext({ storageState: statePath });
const page = await context.newPage();
await page.goto(url, { waitUntil: "domcontentloaded", timeout: 45000 });
await page.waitForTimeout(3000);
console.log(page.url());
} finally {
await browser.close();
}

View file

@ -1,6 +1,10 @@
#!/usr/bin/env bash
# Run designlang against coulomb.social using a captured Playwright storageState.
# Does not print secrets. Requires: ./scripts/capture-auth-state.mjs first.
# Does not print secrets. Requires: ./scripts/capture-auth-state.sh first.
#
# NOTE: designlang's `pack` subcommand does NOT pass --cookie-file into the
# crawler (it calls extractDesignLanguage(url) with no auth options). Use the
# main extract command, which does apply cookies from storageState.
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
@ -8,6 +12,7 @@ AUTH_DIR="${COULOMB_SOCIAL_AUTH_DIR:-$HOME/.config/coulomb-social/auth}"
STATE_PATH="${COULOMB_SOCIAL_STORAGE_STATE:-$AUTH_DIR/storage-state.json}"
OUT_DIR="${COULOMB_SOCIAL_EXTRACT_OUT:-$ROOT/docs/design-extract}"
URL="${COULOMB_SOCIAL_URL:-https://coulomb.social}"
WAIT_MS="${COULOMB_SOCIAL_EXTRACT_WAIT:-5000}"
if [[ ! -f "$STATE_PATH" ]]; then
echo "ERROR: No auth session at $STATE_PATH" >&2
@ -22,21 +27,78 @@ if [[ "$mode" != "600" && "$mode" != "0600" ]]; then
echo "warning: $STATE_PATH mode is $mode (prefer 600)" >&2
fi
echo "==> probing session (no secrets printed)…"
PROBE_URL="$(
cd "$ROOT/scripts" && \
COULOMB_SOCIAL_STORAGE_STATE="$STATE_PATH" \
COULOMB_SOCIAL_URL="$URL" \
node ./probe-auth-session.mjs
)" || PROBE_URL=""
if [[ -n "$PROBE_URL" ]]; then
echo " session lands on: $PROBE_URL"
if [[ "$PROBE_URL" == "https://coulomb.social/" || "$PROBE_URL" == "https://coulomb.social" ]]; then
echo "warning: session still on site root — may be guest; re-run capture-auth-state.sh if extract looks empty" >&2
fi
fi
mkdir -p "$OUT_DIR"
echo "==> designlang extract"
echo "==> designlang extract (main command — cookies applied)"
echo " url: $URL"
echo " auth: $STATE_PATH (session file present; not printed)"
echo " out: $OUT_DIR"
echo " wait: ${WAIT_MS}ms"
echo " extra: $*"
# Global flags (auth, name) must precede the subcommand; pack only accepts -o/--with-clone/--open.
# --cookie-file accepts Playwright storageState JSON.
# Extra args after -- are appended to pack (e.g. --with-clone).
mkdir -p "$(dirname "$OUT_DIR")"
exec npx --yes designlang \
# Main command supports --cookie-file. Prefer a rich capture of the live app UI.
set +e
npx --yes designlang "$URL" \
--cookie-file "$STATE_PATH" \
--name coulomb-social \
pack "$URL" \
-o "$OUT_DIR" \
-n coulomb-social \
--wait "$WAIT_MS" \
--depth "${COULOMB_SOCIAL_EXTRACT_DEPTH:-2}" \
--interactions \
--verbose \
"$@"
dl_ec=$?
set -e
# designlang can crash late while printing summary (Buffer.byteLength on undefined
# content for optional emitters) after already writing the useful artifacts.
if [[ $dl_ec -ne 0 ]]; then
if [[ -f "$OUT_DIR/coulomb-social-design-language.md" && -f "$OUT_DIR/coulomb-social-design-tokens.json" ]]; then
echo "warning: designlang exited $dl_ec after writing core artifacts (known late summary bug); treating as success" >&2
else
echo "ERROR: designlang failed (exit $dl_ec) and core artifacts are missing" >&2
exit "$dl_ec"
fi
fi
# Drop root-level pack leftovers from earlier mistaken `pack` runs (no cookies).
if [[ -d "$ROOT/coulomb-social-design-system" ]]; then
echo "==> removing unauthenticated pack leftover: coulomb-social-design-system/"
rm -rf "$ROOT/coulomb-social-design-system"
fi
# Provenance (no secrets)
cat > "$OUT_DIR/PROVENANCE.md" <<EOF
# Design extract provenance
| Field | Value |
|-------|--------|
| Source | $URL |
| Tool | designlang (main extract, not pack) |
| Captured | $(date -Iseconds) |
| Auth | Playwright storageState via --cookie-file |
| Session probe | ${PROBE_URL:-unknown} |
| designlang exit | $dl_ec |
## Note
Use \`./scripts/run-design-extract.sh\`do **not** use \`designlang pack\` for
authenticated crawls; pack ignores cookies.
EOF
echo "==> done. Inspect: $OUT_DIR"
ls -la "$OUT_DIR" | head -50