From 319dd0046569a4b7eb20168cdcd9df9a89ecf9d3 Mon Sep 17 00:00:00 2001 From: tegwick Date: Sun, 9 Aug 2026 01:22:15 +0200 Subject: [PATCH] Add designlang public-shell pack; tighten auth capture checks Ran authenticated extract against coulomb.social; session metadata matched anonymous Bubble defaults, so treat docs/design-extract as a public shell baseline (PROVENANCE.md). Capture script now refuses to overwrite storage-state.json with thin anonymous sessions. --- docs/design-extract/LICENSE.txt | 20 + docs/design-extract/PROVENANCE.md | 16 + docs/design-extract/README.md | 63 +++ docs/design-extract/components/anatomy.tsx | 4 + docs/design-extract/extras/prompt-pack.md | 120 ++++++ docs/design-extract/extras/voice.json | 13 + .../prompts/claude-artifacts.md | 13 + docs/design-extract/prompts/cursor.md | 18 + docs/design-extract/prompts/lovable.txt | 12 + docs/design-extract/prompts/recipes/button.md | 28 ++ docs/design-extract/prompts/v0.txt | 20 + docs/design-extract/starter/index.html | 41 ++ .../storybook/.storybook/main.ts | 8 + .../storybook/.storybook/preview.ts | 10 + docs/design-extract/storybook/README.md | 15 + docs/design-extract/storybook/package.json | 26 ++ .../storybook/stories/Tokens.mdx | 15 + .../storybook/stories/tokens.css | 11 + docs/design-extract/storybook/tsconfig.json | 15 + docs/design-extract/tokens/design-tokens.json | 162 ++++++++ .../tokens/figma-variables.json | 361 ++++++++++++++++++ docs/design-extract/tokens/motion-tokens.json | 10 + docs/design-extract/tokens/tailwind.config.js | 109 ++++++ docs/design-extract/tokens/theme.js | 147 +++++++ docs/design-extract/tokens/tokens.flat.json | 127 ++++++ docs/design-extract/tokens/variables.css | 93 +++++ scripts/capture-auth-state.mjs | 44 ++- scripts/run-design-extract.sh | 9 +- 28 files changed, 1524 insertions(+), 6 deletions(-) create mode 100644 docs/design-extract/LICENSE.txt create mode 100644 docs/design-extract/PROVENANCE.md create mode 100644 docs/design-extract/README.md create mode 100644 docs/design-extract/components/anatomy.tsx create mode 100644 docs/design-extract/extras/prompt-pack.md create mode 100644 docs/design-extract/extras/voice.json create mode 100644 docs/design-extract/prompts/claude-artifacts.md create mode 100644 docs/design-extract/prompts/cursor.md create mode 100644 docs/design-extract/prompts/lovable.txt create mode 100644 docs/design-extract/prompts/recipes/button.md create mode 100644 docs/design-extract/prompts/v0.txt create mode 100644 docs/design-extract/starter/index.html create mode 100644 docs/design-extract/storybook/.storybook/main.ts create mode 100644 docs/design-extract/storybook/.storybook/preview.ts create mode 100644 docs/design-extract/storybook/README.md create mode 100644 docs/design-extract/storybook/package.json create mode 100644 docs/design-extract/storybook/stories/Tokens.mdx create mode 100644 docs/design-extract/storybook/stories/tokens.css create mode 100644 docs/design-extract/storybook/tsconfig.json create mode 100644 docs/design-extract/tokens/design-tokens.json create mode 100644 docs/design-extract/tokens/figma-variables.json create mode 100644 docs/design-extract/tokens/motion-tokens.json create mode 100644 docs/design-extract/tokens/tailwind.config.js create mode 100644 docs/design-extract/tokens/theme.js create mode 100644 docs/design-extract/tokens/tokens.flat.json create mode 100644 docs/design-extract/tokens/variables.css diff --git a/docs/design-extract/LICENSE.txt b/docs/design-extract/LICENSE.txt new file mode 100644 index 0000000..f739846 --- /dev/null +++ b/docs/design-extract/LICENSE.txt @@ -0,0 +1,20 @@ +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. diff --git a/docs/design-extract/PROVENANCE.md b/docs/design-extract/PROVENANCE.md new file mode 100644 index 0000000..6a99cf2 --- /dev/null +++ b/docs/design-extract/PROVENANCE.md @@ -0,0 +1,16 @@ +# Design extract provenance + +| 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/` | + +## Next + +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. diff --git a/docs/design-extract/README.md b/docs/design-extract/README.md new file mode 100644 index 0000000..335ed11 --- /dev/null +++ b/docs/design-extract/README.md @@ -0,0 +1,63 @@ +# 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 + +``` + +### 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 +``` diff --git a/docs/design-extract/components/anatomy.tsx b/docs/design-extract/components/anatomy.tsx new file mode 100644 index 0000000..0529c08 --- /dev/null +++ b/docs/design-extract/components/anatomy.tsx @@ -0,0 +1,4 @@ +// Auto-generated by designlang — component anatomy v2. +// Scaffolds. Wire into your token system; not a runtime library. + +import * as React from 'react'; diff --git a/docs/design-extract/extras/prompt-pack.md b/docs/design-extract/extras/prompt-pack.md new file mode 100644 index 0000000..982ace5 --- /dev/null +++ b/docs/design-extract/extras/prompt-pack.md @@ -0,0 +1,120 @@ +# 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 + } + ] +} +``` + diff --git a/docs/design-extract/extras/voice.json b/docs/design-extract/extras/voice.json new file mode 100644 index 0000000..05ef569 --- /dev/null +++ b/docs/design-extract/extras/voice.json @@ -0,0 +1,13 @@ +{ + "tone": "neutral", + "pronoun": "third-person", + "headingStyle": "unknown", + "headingLengthClass": "tight", + "ctaVerbs": [], + "buttonPatterns": [], + "sampleHeadings": [], + "stats": { + "buttons": 0, + "headings": 0 + } +} \ No newline at end of file diff --git a/docs/design-extract/prompts/claude-artifacts.md b/docs/design-extract/prompts/claude-artifacts.md new file mode 100644 index 0000000..1da09db --- /dev/null +++ b/docs/design-extract/prompts/claude-artifacts.md @@ -0,0 +1,13 @@ +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. \ No newline at end of file diff --git a/docs/design-extract/prompts/cursor.md b/docs/design-extract/prompts/cursor.md new file mode 100644 index 0000000..34c8196 --- /dev/null +++ b/docs/design-extract/prompts/cursor.md @@ -0,0 +1,18 @@ +# 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 \ No newline at end of file diff --git a/docs/design-extract/prompts/lovable.txt b/docs/design-extract/prompts/lovable.txt new file mode 100644 index 0000000..b483b09 --- /dev/null +++ b/docs/design-extract/prompts/lovable.txt @@ -0,0 +1,12 @@ +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 \ No newline at end of file diff --git a/docs/design-extract/prompts/recipes/button.md b/docs/design-extract/prompts/recipes/button.md new file mode 100644 index 0000000..81bcbe4 --- /dev/null +++ b/docs/design-extract/prompts/recipes/button.md @@ -0,0 +1,28 @@ +# 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 + } + ] +} +``` \ No newline at end of file diff --git a/docs/design-extract/prompts/v0.txt b/docs/design-extract/prompts/v0.txt new file mode 100644 index 0000000..150772c --- /dev/null +++ b/docs/design-extract/prompts/v0.txt @@ -0,0 +1,20 @@ +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. \ No newline at end of file diff --git a/docs/design-extract/starter/index.html b/docs/design-extract/starter/index.html new file mode 100644 index 0000000..210a8d8 --- /dev/null +++ b/docs/design-extract/starter/index.html @@ -0,0 +1,41 @@ + + + + +coulomb.social starter + + + + +
+

Built from coulomb.social

+

This starter is wired to the tokens in tokens/variables.css. Edit the variables and watch this page change. Drop in your own components and use the same tokens to keep the visual language consistent.

+ Get started +

Generated by designlang. Re-pack with npx designlang pack coulomb.social.

+
+ + diff --git a/docs/design-extract/storybook/.storybook/main.ts b/docs/design-extract/storybook/.storybook/main.ts new file mode 100644 index 0000000..9f1965f --- /dev/null +++ b/docs/design-extract/storybook/.storybook/main.ts @@ -0,0 +1,8 @@ +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; diff --git a/docs/design-extract/storybook/.storybook/preview.ts b/docs/design-extract/storybook/.storybook/preview.ts new file mode 100644 index 0000000..1d8241b --- /dev/null +++ b/docs/design-extract/storybook/.storybook/preview.ts @@ -0,0 +1,10 @@ +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; diff --git a/docs/design-extract/storybook/README.md b/docs/design-extract/storybook/README.md new file mode 100644 index 0000000..7fb1694 --- /dev/null +++ b/docs/design-extract/storybook/README.md @@ -0,0 +1,15 @@ +# Index | Coulomb · Storybook + +Auto-generated by `designlang --storybook`. + +## Stories +_No anatomy detected on the source page._ + +## Run + +``` +npm install +npm run storybook +``` + +Opens at http://localhost:6006. diff --git a/docs/design-extract/storybook/package.json b/docs/design-extract/storybook/package.json new file mode 100644 index 0000000..e772307 --- /dev/null +++ b/docs/design-extract/storybook/package.json @@ -0,0 +1,26 @@ +{ + "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" + } +} \ No newline at end of file diff --git a/docs/design-extract/storybook/stories/Tokens.mdx b/docs/design-extract/storybook/stories/Tokens.mdx new file mode 100644 index 0000000..708ae92 --- /dev/null +++ b/docs/design-extract/storybook/stories/Tokens.mdx @@ -0,0 +1,15 @@ +import { Meta, ColorPalette, ColorItem, Typeset } from '@storybook/blocks'; + + + +# Design tokens + +Extracted from https://coulomb.social by [designlang](https://github.com/Manavarya09/design-extract). + + + + + + + + diff --git a/docs/design-extract/storybook/stories/tokens.css b/docs/design-extract/storybook/stories/tokens.css new file mode 100644 index 0000000..47ecb3f --- /dev/null +++ b/docs/design-extract/storybook/stories/tokens.css @@ -0,0 +1,11 @@ +: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); } diff --git a/docs/design-extract/storybook/tsconfig.json b/docs/design-extract/storybook/tsconfig.json new file mode 100644 index 0000000..68637fc --- /dev/null +++ b/docs/design-extract/storybook/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "Bundler", + "jsx": "react-jsx", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true + }, + "include": [ + "stories/**/*", + ".storybook/**/*" + ] +} \ No newline at end of file diff --git a/docs/design-extract/tokens/design-tokens.json b/docs/design-extract/tokens/design-tokens.json new file mode 100644 index 0000000..4a69a18 --- /dev/null +++ b/docs/design-extract/tokens/design-tokens.json @@ -0,0 +1,162 @@ +{ + "$metadata": { + "generator": "designlang", + "version": "7.0.0", + "spec": "https://design-tokens.github.io/community-group/format/", + "source": "https://coulomb.social", + "generatedAt": "2026-08-08T23:21:16.292Z" + }, + "primitive": { + "color": { + "brand": { + "primary": { + "$value": "#d08728", + "$type": "color" + } + }, + "neutral": { + "n100": { + "$value": "#000000", + "$type": "color" + }, + "n200": { + "$value": "#171717", + "$type": "color" + }, + "n300": { + "$value": "#ffffff", + "$type": "color" + }, + "n400": { + "$value": "#616161", + "$type": "color" + }, + "n500": { + "$value": "#e5e5e5", + "$type": "color" + } + }, + "background": { + "bg0": { + "$value": "#ffffff", + "$type": "color" + }, + "bg1": { + "$value": "#616161", + "$type": "color" + } + }, + "text": { + "text0": { + "$value": "#000000", + "$type": "color" + }, + "text1": { + "$value": "#ffffff", + "$type": "color" + }, + "text2": { + "$value": "#171717", + "$type": "color" + }, + "text3": { + "$value": "#d08728", + "$type": "color" + } + } + }, + "spacing": { + "s0": { + "$value": "2px", + "$type": "dimension" + }, + "s1": { + "$value": "32px", + "$type": "dimension" + }, + "s2": { + "$value": "68px", + "$type": "dimension" + } + }, + "radius": { + "r0": { + "$value": "4px", + "$type": "dimension" + }, + "r1": { + "$value": "8px", + "$type": "dimension" + } + }, + "shadow": { + "sh0": { + "$value": "rgb(97, 97, 97) 2px 2px 8px 0px", + "$type": "shadow" + } + }, + "fontFamily": { + "f0": { + "$value": "Times New Roman", + "$type": "fontFamily" + }, + "f1": { + "$value": "Helvetica", + "$type": "fontFamily" + }, + "f2": { + "$value": "Inter", + "$type": "fontFamily" + }, + "f3": { + "$value": "Arial", + "$type": "fontFamily" + } + } + }, + "semantic": { + "color": { + "action": { + "primary": { + "$value": "{primitive.color.brand.primary}", + "$type": "color" + } + }, + "surface": { + "default": { + "$value": "{primitive.color.background.bg0}", + "$type": "color" + } + }, + "text": { + "body": { + "$value": "{primitive.color.text.text0}", + "$type": "color" + } + } + }, + "typography": { + "body": { + "$value": { + "fontFamily": "Times New Roman", + "fontSize": "48px", + "fontWeight": "700", + "lineHeight": "67.2px" + }, + "$type": "typography" + } + }, + "radius": { + "control": { + "$value": "{primitive.radius.r0}", + "$type": "dimension" + } + }, + "shadow": { + "elevated": { + "$value": "{primitive.shadow.sh0}", + "$type": "shadow" + } + } + } +} \ No newline at end of file diff --git a/docs/design-extract/tokens/figma-variables.json b/docs/design-extract/tokens/figma-variables.json new file mode 100644 index 0000000..9626fdc --- /dev/null +++ b/docs/design-extract/tokens/figma-variables.json @@ -0,0 +1,361 @@ +{ + "collections": [ + { + "name": "Brand", + "modes": [ + "light" + ], + "variables": [ + { + "name": "color/primary", + "type": "COLOR", + "values": { + "light": { + "r": 0.8156862745098039, + "g": 0.5294117647058824, + "b": 0.1568627450980392, + "a": 1 + } + } + }, + { + "name": "color/neutral/50", + "type": "COLOR", + "values": { + "light": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + } + } + }, + { + "name": "color/neutral/100", + "type": "COLOR", + "values": { + "light": { + "r": 0.09019607843137255, + "g": 0.09019607843137255, + "b": 0.09019607843137255, + "a": 1 + } + } + }, + { + "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, + "g": 0.3803921568627451, + "b": 0.3803921568627451, + "a": 1 + } + } + }, + { + "name": "color/neutral/400", + "type": "COLOR", + "values": { + "light": { + "r": 0.8980392156862745, + "g": 0.8980392156862745, + "b": 0.8980392156862745, + "a": 1 + } + } + }, + { + "name": "color/background/default", + "type": "COLOR", + "values": { + "light": { + "r": 1, + "g": 1, + "b": 1, + "a": 1 + } + } + }, + { + "name": "color/background/1", + "type": "COLOR", + "values": { + "light": { + "r": 0.3803921568627451, + "g": 0.3803921568627451, + "b": 0.3803921568627451, + "a": 1 + } + } + }, + { + "name": "color/text/default", + "type": "COLOR", + "values": { + "light": { + "r": 0, + "g": 0, + "b": 0, + "a": 1 + } + } + }, + { + "name": "color/text/1", + "type": "COLOR", + "values": { + "light": { + "r": 1, + "g": 1, + "b": 1, + "a": 1 + } + } + }, + { + "name": "color/text/2", + "type": "COLOR", + "values": { + "light": { + "r": 0.09019607843137255, + "g": 0.09019607843137255, + "b": 0.09019607843137255, + "a": 1 + } + } + }, + { + "name": "color/text/3", + "type": "COLOR", + "values": { + "light": { + "r": 0.8156862745098039, + "g": 0.5294117647058824, + "b": 0.1568627450980392, + "a": 1 + } + } + } + ] + }, + { + "name": "Typography", + "modes": [ + "default" + ], + "variables": [ + { + "name": "font/size/48", + "type": "FLOAT", + "values": { + "default": 48 + } + }, + { + "name": "font/weight/48", + "type": "FLOAT", + "values": { + "default": 700 + } + }, + { + "name": "font/lineHeight/48", + "type": "FLOAT", + "values": { + "default": 67.2 + } + }, + { + "name": "font/size/32", + "type": "FLOAT", + "values": { + "default": 32 + } + }, + { + "name": "font/weight/32", + "type": "FLOAT", + "values": { + "default": 600 + } + }, + { + "name": "font/lineHeight/32", + "type": "FLOAT", + "values": { + "default": 44.8 + } + }, + { + "name": "font/size/18", + "type": "FLOAT", + "values": { + "default": 18 + } + }, + { + "name": "font/weight/18", + "type": "FLOAT", + "values": { + "default": 600 + } + }, + { + "name": "font/lineHeight/18", + "type": "FLOAT", + "values": { + "default": 25.2 + } + }, + { + "name": "font/size/16", + "type": "FLOAT", + "values": { + "default": 16 + } + }, + { + "name": "font/weight/16", + "type": "FLOAT", + "values": { + "default": 400 + } + }, + { + "name": "font/size/14", + "type": "FLOAT", + "values": { + "default": 14 + } + }, + { + "name": "font/weight/14", + "type": "FLOAT", + "values": { + "default": 500 + } + }, + { + "name": "font/lineHeight/14", + "type": "FLOAT", + "values": { + "default": 19.6 + } + }, + { + "name": "font/size/13.3333", + "type": "FLOAT", + "values": { + "default": 13.3333 + } + }, + { + "name": "font/weight/13.3333", + "type": "FLOAT", + "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 + } + } + ] + }, + { + "name": "Spacing", + "modes": [ + "default" + ], + "variables": [ + { + "name": "spacing/2", + "type": "FLOAT", + "values": { + "default": 2 + } + }, + { + "name": "spacing/32", + "type": "FLOAT", + "values": { + "default": 32 + } + }, + { + "name": "spacing/68", + "type": "FLOAT", + "values": { + "default": 68 + } + }, + { + "name": "radius/sm", + "type": "FLOAT", + "values": { + "default": 4 + } + }, + { + "name": "radius/md", + "type": "FLOAT", + "values": { + "default": 8 + } + } + ] + } + ] +} \ No newline at end of file diff --git a/docs/design-extract/tokens/motion-tokens.json b/docs/design-extract/tokens/motion-tokens.json new file mode 100644 index 0000000..404619d --- /dev/null +++ b/docs/design-extract/tokens/motion-tokens.json @@ -0,0 +1,10 @@ +{ + "$description": "Motion tokens extracted by designlang", + "duration": {}, + "easing": {}, + "spring": {}, + "$meta": { + "feel": "mixed", + "scrollLinked": true + } +} \ No newline at end of file diff --git a/docs/design-extract/tokens/tailwind.config.js b/docs/design-extract/tokens/tailwind.config.js new file mode 100644 index 0000000..fc46802 --- /dev/null +++ b/docs/design-extract/tokens/tailwind.config.js @@ -0,0 +1,109 @@ +/** @type {import('tailwindcss').Config} */ +export default { + theme: { + extend: { + colors: { + primary: { + '50': 'hsl(34, 68%, 97%)', + '100': 'hsl(34, 68%, 94%)', + '200': 'hsl(34, 68%, 86%)', + '300': 'hsl(34, 68%, 76%)', + '400': 'hsl(34, 68%, 64%)', + '500': 'hsl(34, 68%, 50%)', + '600': 'hsl(34, 68%, 40%)', + '700': 'hsl(34, 68%, 32%)', + '800': 'hsl(34, 68%, 24%)', + '900': 'hsl(34, 68%, 16%)', + '950': 'hsl(34, 68%, 10%)', + DEFAULT: '#d08728' + }, + 'neutral-50': '#000000', + 'neutral-100': '#171717', + 'neutral-200': '#ffffff', + 'neutral-300': '#616161', + 'neutral-400': '#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', + { + lineHeight: '19.6px' + } + ], + '16': [ + '16px', + { + lineHeight: 'normal' + } + ], + '18': [ + '18px', + { + lineHeight: '25.2px' + } + ], + '32': [ + '32px', + { + lineHeight: '44.8px' + } + ], + '48': [ + '48px', + { + lineHeight: '67.2px' + } + ], + '13.3333': [ + '13.3333px', + { + lineHeight: 'normal' + } + ] + }, + spacing: { + '1': '2px', + '16': '32px', + '34': '68px' + }, + borderRadius: { + sm: '4px', + md: '8px' + }, + boxShadow: { + md: 'rgb(97, 97, 97) 2px 2px 8px 0px' + }, + container: { + center: true, + padding: '32px' + }, + maxWidth: { + container: '1080px' + } +}, + }, +}; diff --git a/docs/design-extract/tokens/theme.js b/docs/design-extract/tokens/theme.js new file mode 100644 index 0000000..0f65492 --- /dev/null +++ b/docs/design-extract/tokens/theme.js @@ -0,0 +1,147 @@ +// React Theme — extracted from https://coulomb.social +// Compatible with: Chakra UI, Stitches, Vanilla Extract, or any CSS-in-JS + +/** + * TypeScript type definition for this theme: + * + * interface Theme { + * colors: { + primary: string; + background: string; + foreground: string; + neutral50: string; + neutral100: string; + neutral200: string; + neutral300: string; + neutral400: string; + * }; + * fonts: { + body: string; + * }; + * fontSizes: { + '8': string; + '12': string; + '14': string; + '16': string; + '18': string; + '32': string; + '48': string; + '13.3333': string; + * }; + * space: { + '2': string; + '32': string; + '68': string; + * }; + * radii: { + sm: string; + md: string; + * }; + * shadows: { + md: string; + * }; + * states: { + * hover: { opacity: number }; + * focus: { opacity: number }; + * active: { opacity: number }; + * disabled: { opacity: number }; + * }; + * } + */ + +export const theme = { + "colors": { + "primary": "#d08728", + "background": "#ffffff", + "foreground": "#000000", + "neutral50": "#000000", + "neutral100": "#171717", + "neutral200": "#ffffff", + "neutral300": "#616161", + "neutral400": "#e5e5e5" + }, + "fonts": { + "body": "'Arial', sans-serif" + }, + "fontSizes": { + "8": "8px", + "12": "12px", + "14": "14px", + "16": "16px", + "18": "18px", + "32": "32px", + "48": "48px", + "13.3333": "13.3333px" + }, + "space": { + "2": "2px", + "32": "32px", + "68": "68px" + }, + "radii": { + "sm": "4px", + "md": "8px" + }, + "shadows": { + "md": "rgb(97, 97, 97) 2px 2px 8px 0px" + }, + "states": { + "hover": { + "opacity": 0.08 + }, + "focus": { + "opacity": 0.12 + }, + "active": { + "opacity": 0.16 + }, + "disabled": { + "opacity": 0.38 + } + } +}; + +// MUI v5 theme +export const muiTheme = { + "palette": { + "primary": { + "main": "#d08728", + "light": "hsl(34, 68%, 64%)", + "dark": "hsl(34, 68%, 34%)" + }, + "background": { + "default": "#ffffff", + "paper": "#616161" + }, + "text": { + "primary": "#000000", + "secondary": "#ffffff" + } + }, + "typography": { + "fontFamily": "'Times New Roman', sans-serif", + "h1": { + "fontSize": "32px", + "fontWeight": "600", + "lineHeight": "44.8px" + }, + "body1": { + "fontSize": "16px", + "fontWeight": "400", + "lineHeight": "normal" + }, + "body2": { + "fontSize": "13.3333px", + "fontWeight": "400", + "lineHeight": "normal" + } + }, + "shape": { + "borderRadius": 8 + }, + "shadows": [ + "rgb(97, 97, 97) 2px 2px 8px 0px" + ] +}; + +export default theme; diff --git a/docs/design-extract/tokens/tokens.flat.json b/docs/design-extract/tokens/tokens.flat.json new file mode 100644 index 0000000..48f437f --- /dev/null +++ b/docs/design-extract/tokens/tokens.flat.json @@ -0,0 +1,127 @@ +{ + "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": {} +} \ No newline at end of file diff --git a/docs/design-extract/tokens/variables.css b/docs/design-extract/tokens/variables.css new file mode 100644 index 0000000..2e12413 --- /dev/null +++ b/docs/design-extract/tokens/variables.css @@ -0,0 +1,93 @@ +:root { + /* Colors — Primary */ + --color-primary: #d08728; + + /* Colors — Neutrals */ + --color-neutral-50: #000000; + --color-neutral-100: #171717; + --color-neutral-200: #ffffff; + --color-neutral-300: #616161; + --color-neutral-400: #e5e5e5; + + /* Colors — Backgrounds */ + --color-bg: #ffffff; + --color-bg-1: #616161; + + /* Colors — Text */ + --color-text: #000000; + --color-text-1: #ffffff; + --color-text-2: #171717; + --color-text-3: #d08728; + + /* 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; + + /* Typography — Scale */ + --font-size-48: 48px; + --font-size-32: 32px; + --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-32: 32px; + --spacing-68: 68px; + + /* Border Radius */ + --radius-sm: 4px; + --radius-md: 8px; + + /* Box Shadows */ + --shadow-md: rgb(97, 97, 97) 2px 2px 8px 0px; + + /* Original Site Variables */ + /* — colors — */ + --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 — */ + --font_default: 'Lato'; + --font_bTRUx_default: "Inter"; + --font_bTRUt_default: "Inter"; + /* — semantic — */ + success: [object Object]; + warning: [object Object]; + error: [object Object]; + info: [object Object]; + +} \ No newline at end of file diff --git a/scripts/capture-auth-state.mjs b/scripts/capture-auth-state.mjs index 5b4b2b2..736a6e4 100755 --- a/scripts/capture-auth-state.mjs +++ b/scripts/capture-auth-state.mjs @@ -137,16 +137,54 @@ async function main() { } const state = await context.storageState(); + const cookieCount = state.cookies?.length ?? 0; + const originCount = state.origins?.length ?? 0; + 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) { + console.error(""); + console.error( + "WARNING: This looks like an anonymous Bubble session, not a logged-in user.", + ); + console.error( + ` cookies=${cookieCount} (only default coulomb_* names)`, + ); + 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; + } + writeFileSync(STATE_PATH, JSON.stringify(state, null, 2) + "\n", { mode: 0o600, }); chmodSync(STATE_PATH, 0o600); - const cookieCount = state.cookies?.length ?? 0; - const originCount = state.origins?.length ?? 0; console.log(""); console.log( - `Saved storageState (${cookieCount} cookies, ${originCount} origins).`, + `Saved storageState (${cookieCount} cookies, ${originCount} origins, localStorage keys: ${lsKeys.length}).`, ); console.log(`File: ${STATE_PATH}`); console.log("Next: ./scripts/run-design-extract.sh"); diff --git a/scripts/run-design-extract.sh b/scripts/run-design-extract.sh index 2a2bb98..712b18c 100755 --- a/scripts/run-design-extract.sh +++ b/scripts/run-design-extract.sh @@ -30,10 +30,13 @@ echo " auth: $STATE_PATH (session file present; not printed)" echo " out: $OUT_DIR" echo " extra: $*" -# Default pack is useful for agent rebuild; caller can pass more flags. +# Global flags (auth, name) must precede the subcommand; pack only accepts -o/--with-clone/--open. # --cookie-file accepts Playwright storageState JSON. -exec npx --yes designlang pack "$URL" \ +# Extra args after -- are appended to pack (e.g. --with-clone). +mkdir -p "$(dirname "$OUT_DIR")" +exec npx --yes designlang \ --cookie-file "$STATE_PATH" \ - -o "$OUT_DIR" \ --name coulomb-social \ + pack "$URL" \ + -o "$OUT_DIR" \ "$@"