vibe-ui-suite 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs ADDED
@@ -0,0 +1,243 @@
1
+ #!/usr/bin/env node
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ import * as readline from 'readline';
5
+ import { COMPONENT_REGISTRY } from './registry/components';
6
+ import { VISUAL_CHEMISTRIES } from './index';
7
+ const VERSION = '4.0.0';
8
+ function printBanner() {
9
+ console.log(`
10
+ \x1b[35m ▲ VIBE UI CLI v${VERSION}\x1b[0m
11
+ \x1b[90mDeterministic UI contracts & component primitives for AI coding assistants\x1b[0m
12
+ `);
13
+ }
14
+ function printHelp() {
15
+ printBanner();
16
+ console.log(`\x1b[1mUSAGE:\x1b[0m
17
+ npx vibe-ui-suite <command> [options]
18
+ npx @omid-io/tokens <command> [options]
19
+ vibe-ui <command> [options]
20
+
21
+ \x1b[1mCOMMANDS:\x1b[0m
22
+ \x1b[32minit\x1b[0m Initialize Vibe UI contracts, OKLCH tokens & AI rules in current project
23
+ \x1b[32madd <component>\x1b[0m Add an accessible, AI-native component template to your project
24
+ \x1b[32mlist\x1b[0m List all available component primitives in the registry
25
+
26
+ \x1b[1mOPTIONS:\x1b[0m
27
+ -f, --force Overwrite existing files (creates automated .bak backups)
28
+ --dry-run Preview file operations without making actual modifications
29
+ -v, --version Show CLI version
30
+ -h, --help Show help menu
31
+
32
+ \x1b[1mEXAMPLES:\x1b[0m
33
+ npx vibe-ui-suite init
34
+ npx vibe-ui-suite init --dry-run
35
+ npx vibe-ui-suite add thinking-drawer
36
+ npx vibe-ui-suite add thinking-drawer --force
37
+ `);
38
+ }
39
+ function prompt(rl, query) {
40
+ return new Promise((resolve) => rl.question(query, resolve));
41
+ }
42
+ function safeWriteFile(filePath, content, options) {
43
+ const relPath = path.relative(process.cwd(), filePath);
44
+ if (options.dryRun) {
45
+ console.log(` \x1b[34m[dry-run]\x1b[0m Would write: ${relPath}`);
46
+ return { written: false, skipped: false };
47
+ }
48
+ if (fs.existsSync(filePath) && !options.force) {
49
+ console.log(` \x1b[33m[skip]\x1b[0m ${relPath} already exists. (Use --force to overwrite)`);
50
+ return { written: false, skipped: true };
51
+ }
52
+ if (fs.existsSync(filePath) && options.force) {
53
+ const backupPath = `${filePath}.bak`;
54
+ fs.copyFileSync(filePath, backupPath);
55
+ fs.writeFileSync(filePath, content, 'utf-8');
56
+ console.log(` \x1b[35m[backup]\x1b[0m Backed up existing file to ${path.relative(process.cwd(), backupPath)}`);
57
+ return { written: true, skipped: false, backup: backupPath };
58
+ }
59
+ fs.writeFileSync(filePath, content, 'utf-8');
60
+ return { written: true, skipped: false };
61
+ }
62
+ const CONTRACT_RULES = `# Vibe UI Design & Code Quality Contract
63
+ # Generated via npx vibe-ui-suite init
64
+
65
+ Follow strict anti-slop guidelines:
66
+ - Zero raw unicode emojis (use inline SVGs only)
67
+ - Strict WCAG 2.2 AA contrast (>= 4.5:1 body, >= 3.0:1 headings)
68
+ - Use typed OKLCH color spaces for perceptual accuracy
69
+ - Strict maximum of 3 backdrop-filter / glass layers
70
+ - Semantic RTL: preserve physical macro coordinate stability
71
+ `;
72
+ async function handleInit(options) {
73
+ printBanner();
74
+ if (options.dryRun) {
75
+ console.log('\x1b[34m[DRY-RUN MODE ACTIVATED: No files will be modified on disk]\x1b[0m\n');
76
+ }
77
+ const rl = readline.createInterface({
78
+ input: process.stdin,
79
+ output: process.stdout,
80
+ });
81
+ try {
82
+ console.log('\x1b[1mInitialize Vibe UI in current workspace:\x1b[0m\n');
83
+ // 1. Select Visual Chemistry
84
+ console.log('\x1b[36m1. Select Visual Chemistry:\x1b[0m');
85
+ console.log(' [1] Minimalist SaaS (Monochrome restraint, high signal - Recommended)');
86
+ console.log(' [2] Luxury Glass 2.0 (Specular Fresnel, deep dark, gold accents)');
87
+ console.log(' [3] Neobrutalism (Hard 3px black offset shadows, bold high saturation)');
88
+ console.log(' [4] Swiss Editorial (Asymmetric grid, typography-first, high contrast)');
89
+ console.log(' [5] Stripe Crisp Light (Developer docs, precision micro-borders)');
90
+ const chemChoice = (await prompt(rl, 'Choice [1-5] (default: 1): ')).trim() || '1';
91
+ const chemMap = {
92
+ '1': 'MINIMALIST_SAAS',
93
+ '2': 'LUXURY_GLASS_2',
94
+ '3': 'NEOBRUTALISM',
95
+ '4': 'SWISS_EDITORIAL',
96
+ '5': 'STRIPE_CRISP_LIGHT',
97
+ };
98
+ const selectedChemKey = chemMap[chemChoice] || 'MINIMALIST_SAAS';
99
+ const selectedChem = VISUAL_CHEMISTRIES[selectedChemKey];
100
+ // 2. Select AI Editor
101
+ console.log('\n\x1b[36m2. Select AI Coding Environment:\x1b[0m');
102
+ console.log(' [1] Cursor (.cursorrules - Recommended)');
103
+ console.log(' [2] Claude Code (CLAUDE.md)');
104
+ console.log(' [3] Windsurf (.windsurfrules)');
105
+ console.log(' [4] All of the above');
106
+ const editorChoice = (await prompt(rl, 'Choice [1-4] (default: 1): ')).trim() || '1';
107
+ // 3. Write contract rules safely
108
+ const cwd = process.cwd();
109
+ const createdFiles = [];
110
+ if (editorChoice === '1' || editorChoice === '4') {
111
+ const res = safeWriteFile(path.join(cwd, '.cursorrules'), CONTRACT_RULES, options);
112
+ if (res.written)
113
+ createdFiles.push('.cursorrules');
114
+ }
115
+ if (editorChoice === '2' || editorChoice === '4') {
116
+ const claudePath = path.join(cwd, 'CLAUDE.md');
117
+ if (options.dryRun) {
118
+ console.log(' \x1b[34m[dry-run]\x1b[0m Would update CLAUDE.md');
119
+ }
120
+ else if (fs.existsSync(claudePath)) {
121
+ fs.appendFileSync(claudePath, `\n\n${CONTRACT_RULES}`, 'utf-8');
122
+ createdFiles.push('CLAUDE.md (appended)');
123
+ }
124
+ else {
125
+ const res = safeWriteFile(claudePath, CONTRACT_RULES, options);
126
+ if (res.written)
127
+ createdFiles.push('CLAUDE.md');
128
+ }
129
+ }
130
+ if (editorChoice === '3' || editorChoice === '4') {
131
+ const res = safeWriteFile(path.join(cwd, '.windsurfrules'), CONTRACT_RULES, options);
132
+ if (res.written)
133
+ createdFiles.push('.windsurfrules');
134
+ }
135
+ // 4. Generate CSS Tokens file safely
136
+ const cssContent = `:root {
137
+ /* Vibe UI Chemistry: ${selectedChem.name} (${selectedChem.id}) */
138
+ --vibe-canvas: ${selectedChem.colors.canvas};
139
+ --vibe-surface: ${selectedChem.colors.surface};
140
+ --vibe-border: ${selectedChem.colors.border};
141
+ --vibe-primary-accent: ${selectedChem.colors.primaryAccent};
142
+ --vibe-text-primary: ${selectedChem.colors.textPrimary};
143
+ --vibe-text-muted: ${selectedChem.colors.textMuted};
144
+ --vibe-ring: ${selectedChem.colors.ring};
145
+ }
146
+ `;
147
+ const cssPath = path.join(cwd, 'vibe-tokens.css');
148
+ const cssRes = safeWriteFile(cssPath, cssContent, options);
149
+ if (cssRes.written)
150
+ createdFiles.push('vibe-tokens.css');
151
+ console.log('\n\x1b[32m✔ Initialized successfully!\x1b[0m');
152
+ if (createdFiles.length > 0) {
153
+ console.log('\x1b[90mGenerated/Updated files:\x1b[0m');
154
+ createdFiles.forEach((f) => console.log(` + ${f}`));
155
+ }
156
+ console.log(`
157
+ \x1b[1mNext Steps:\x1b[0m
158
+ 1. Import \x1b[35mvibe-tokens.css\x1b[0m into your layout or globals.css
159
+ 2. Run \x1b[32mnpx @omid-io/tokens add thinking-drawer\x1b[0m to add your first AI component
160
+ `);
161
+ }
162
+ finally {
163
+ rl.close();
164
+ }
165
+ }
166
+ function handleAdd(componentName, options = { force: false, dryRun: false }) {
167
+ if (!componentName) {
168
+ console.log('\x1b[33mError: Please specify a component to add.\x1b[0m\n');
169
+ handleList();
170
+ console.log('\nUsage: npx @omid-io/tokens add <component> [--force]');
171
+ process.exit(1);
172
+ return;
173
+ }
174
+ const comp = COMPONENT_REGISTRY[componentName.toLowerCase()];
175
+ if (!comp) {
176
+ console.log(`\x1b[31mError: Unknown component "${componentName}".\x1b[0m\n`);
177
+ handleList();
178
+ process.exit(1);
179
+ return;
180
+ }
181
+ const cwd = process.cwd();
182
+ const targetDir = path.join(cwd, 'components', 'vibe-ui');
183
+ if (!options.dryRun) {
184
+ fs.mkdirSync(targetDir, { recursive: true });
185
+ }
186
+ const targetFile = path.join(targetDir, comp.filename);
187
+ const writeRes = safeWriteFile(targetFile, comp.code, options);
188
+ if (writeRes.skipped) {
189
+ console.log(`\n\x1b[33mWarning: Component already exists at components/vibe-ui/${comp.filename}\x1b[0m`);
190
+ console.log(`To overwrite with automated .bak backup, re-run with:`);
191
+ console.log(` \x1b[32mnpx @omid-io/tokens add ${componentName} --force\x1b[0m\n`);
192
+ return;
193
+ }
194
+ if (writeRes.written) {
195
+ console.log(`\x1b[32m✔ Added component "${comp.name}"!\x1b[0m`);
196
+ console.log(` \x1b[90mLocation:\x1b[0m components/vibe-ui/${comp.filename}`);
197
+ console.log(` \x1b[90mDescription:\x1b[0m ${comp.description}\n`);
198
+ console.log(`\x1b[1mUsage in your page or view:\x1b[0m`);
199
+ console.log(` import { ${comp.filename.replace('.tsx', '')} } from '@/components/vibe-ui/${comp.filename.replace('.tsx', '')}';\n`);
200
+ }
201
+ }
202
+ function handleList() {
203
+ console.log('\x1b[1mAvailable Vibe UI Components:\x1b[0m');
204
+ Object.values(COMPONENT_REGISTRY).forEach((comp) => {
205
+ console.log(` \x1b[32m${comp.name.padEnd(18)}\x1b[0m \x1b[90m${comp.description}\x1b[0m`);
206
+ });
207
+ }
208
+ async function main() {
209
+ const rawArgs = process.argv.slice(2);
210
+ const force = rawArgs.includes('--force') || rawArgs.includes('-f');
211
+ const dryRun = rawArgs.includes('--dry-run');
212
+ const filteredArgs = rawArgs.filter((a) => !['--force', '-f', '--dry-run'].includes(a));
213
+ const cmd = filteredArgs[0]?.toLowerCase();
214
+ const options = { force, dryRun };
215
+ if (!cmd || cmd === '--help' || cmd === '-h') {
216
+ printHelp();
217
+ return;
218
+ }
219
+ if (cmd === '--version' || cmd === '-v') {
220
+ console.log(`v${VERSION}`);
221
+ return;
222
+ }
223
+ switch (cmd) {
224
+ case 'init':
225
+ await handleInit(options);
226
+ break;
227
+ case 'add':
228
+ handleAdd(filteredArgs[1], options);
229
+ break;
230
+ case 'list':
231
+ printBanner();
232
+ handleList();
233
+ break;
234
+ default:
235
+ console.log(`\x1b[31mUnknown command "${cmd}".\x1b[0m`);
236
+ printHelp();
237
+ process.exit(1);
238
+ }
239
+ }
240
+ main().catch((err) => {
241
+ console.error('\x1b[31mFatal CLI error:\x1b[0m', err);
242
+ process.exit(1);
243
+ });
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @vibe-ui/tokens
3
+ * Typed OKLCH design tokens, physics curves, and contrast utilities.
4
+ */
5
+ export type VisualChemistryId = 'MINIMALIST_SAAS' | 'LUXURY_GLASS_2' | 'NEOBRUTALISM' | 'SWISS_EDITORIAL' | 'STRIPE_CRISP_LIGHT';
6
+ export interface ChemistryColors {
7
+ canvas: string;
8
+ surface: string;
9
+ border: string;
10
+ primaryAccent: string;
11
+ textPrimary: string;
12
+ textMuted: string;
13
+ ring: string;
14
+ }
15
+ export interface ChemistryTypography {
16
+ display: string;
17
+ body: string;
18
+ mono: string;
19
+ }
20
+ export interface ChemistryPhysics {
21
+ springStiffness: number;
22
+ dampingRatio: number;
23
+ lerpAlpha: string;
24
+ }
25
+ export interface VisualChemistry {
26
+ id: VisualChemistryId;
27
+ name: string;
28
+ tagline: string;
29
+ colors: ChemistryColors;
30
+ typography: ChemistryTypography;
31
+ physics: ChemistryPhysics;
32
+ }
33
+ export declare const VISUAL_CHEMISTRIES: Record<VisualChemistryId, VisualChemistry>;
34
+ /** Easing curves adhering to Vibe UI motion standards */
35
+ export declare const MOTION_CURVES: {
36
+ readonly naturalSpring: "cubic-bezier(0.16, 1, 0.3, 1)";
37
+ readonly responsiveSnap: "cubic-bezier(0.25, 1, 0.5, 1)";
38
+ readonly crispEnter: "cubic-bezier(0, 0, 0.2, 1)";
39
+ readonly crispExit: "cubic-bezier(0.4, 0, 1, 1)";
40
+ };
41
+ /** Relative luminance formula conforming to WCAG 2.2 */
42
+ export declare function getRelativeLuminance(r: number, g: number, b: number): number;
43
+ /** Contrast ratio between two luminance values */
44
+ export declare function getContrastRatio(lumA: number, lumB: number): number;
package/dist/index.js ADDED
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ /**
3
+ * @vibe-ui/tokens
4
+ * Typed OKLCH design tokens, physics curves, and contrast utilities.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.MOTION_CURVES = exports.VISUAL_CHEMISTRIES = void 0;
8
+ exports.getRelativeLuminance = getRelativeLuminance;
9
+ exports.getContrastRatio = getContrastRatio;
10
+ exports.VISUAL_CHEMISTRIES = {
11
+ MINIMALIST_SAAS: {
12
+ id: 'MINIMALIST_SAAS',
13
+ name: 'Minimalist SaaS',
14
+ tagline: 'High-signal B2B productivity with subtle borders and monochrome restraint',
15
+ colors: {
16
+ canvas: 'oklch(0.14 0.005 264)',
17
+ surface: 'oklch(0.18 0.008 264)',
18
+ border: 'oklch(0.28 0.01 264)',
19
+ primaryAccent: 'oklch(0.65 0.22 260)',
20
+ textPrimary: 'oklch(0.98 0.002 264)',
21
+ textMuted: 'oklch(0.65 0.015 264)',
22
+ ring: 'oklch(0.65 0.22 260)',
23
+ },
24
+ typography: {
25
+ display: 'Inter, system-ui, sans-serif',
26
+ body: 'Inter, system-ui, sans-serif',
27
+ mono: 'JetBrains Mono, Menlo, monospace',
28
+ },
29
+ physics: {
30
+ springStiffness: 280,
31
+ dampingRatio: 0.85,
32
+ lerpAlpha: '1 - Math.exp(-14 * dt)',
33
+ },
34
+ },
35
+ LUXURY_GLASS_2: {
36
+ id: 'LUXURY_GLASS_2',
37
+ name: 'Luxury Glassmorphism 2.0',
38
+ tagline: 'Deep dark substrates with specular highlights and gold accents',
39
+ colors: {
40
+ canvas: 'oklch(0.12 0.015 280)',
41
+ surface: 'oklch(0.18 0.02 280 / 0.75)',
42
+ border: 'oklch(0.75 0.15 85 / 0.35)',
43
+ primaryAccent: 'oklch(0.78 0.16 85)',
44
+ textPrimary: 'oklch(0.98 0.005 85)',
45
+ textMuted: 'oklch(0.70 0.03 85)',
46
+ ring: 'oklch(0.78 0.16 85)',
47
+ },
48
+ typography: {
49
+ display: 'Cinzel, Playfair Display, serif',
50
+ body: 'Plus Jakarta Sans, sans-serif',
51
+ mono: 'JetBrains Mono, monospace',
52
+ },
53
+ physics: {
54
+ springStiffness: 180,
55
+ dampingRatio: 0.92,
56
+ lerpAlpha: '1 - Math.exp(-8 * dt)',
57
+ },
58
+ },
59
+ NEOBRUTALISM: {
60
+ id: 'NEOBRUTALISM',
61
+ name: 'Neobrutalism',
62
+ tagline: 'High-contrast saturated flat cards with hard 3px black offset shadows',
63
+ colors: {
64
+ canvas: 'oklch(0.96 0.01 95)',
65
+ surface: 'oklch(0.99 0.002 95)',
66
+ border: 'oklch(0.15 0.01 95)',
67
+ primaryAccent: 'oklch(0.82 0.20 135)',
68
+ textPrimary: 'oklch(0.12 0.01 95)',
69
+ textMuted: 'oklch(0.35 0.02 95)',
70
+ ring: 'oklch(0.15 0.01 95)',
71
+ },
72
+ typography: {
73
+ display: 'Space Grotesk, Syne, sans-serif',
74
+ body: 'Space Grotesk, sans-serif',
75
+ mono: 'Space Mono, monospace',
76
+ },
77
+ physics: {
78
+ springStiffness: 450,
79
+ dampingRatio: 0.7,
80
+ lerpAlpha: '1 - Math.exp(-22 * dt)',
81
+ },
82
+ },
83
+ SWISS_EDITORIAL: {
84
+ id: 'SWISS_EDITORIAL',
85
+ name: 'Swiss Editorial',
86
+ tagline: 'Asymmetric typography-first layout inspired by International Typographic Style',
87
+ colors: {
88
+ canvas: 'oklch(0.97 0.005 80)',
89
+ surface: 'oklch(0.93 0.008 80)',
90
+ border: 'oklch(0.20 0.005 80)',
91
+ primaryAccent: 'oklch(0.58 0.24 28)',
92
+ textPrimary: 'oklch(0.15 0.005 80)',
93
+ textMuted: 'oklch(0.42 0.01 80)',
94
+ ring: 'oklch(0.58 0.24 28)',
95
+ },
96
+ typography: {
97
+ display: 'Helvetica Neue, Arial, sans-serif',
98
+ body: 'Newsreader, Georgia, serif',
99
+ mono: 'Courier New, monospace',
100
+ },
101
+ physics: {
102
+ springStiffness: 300,
103
+ dampingRatio: 0.9,
104
+ lerpAlpha: '1 - Math.exp(-12 * dt)',
105
+ },
106
+ },
107
+ STRIPE_CRISP_LIGHT: {
108
+ id: 'STRIPE_CRISP_LIGHT',
109
+ name: 'Stripe Crisp Light',
110
+ tagline: 'Ultra-clean developer-first documentation layout with refined micro-borders',
111
+ colors: {
112
+ canvas: 'oklch(0.985 0.002 247.8)',
113
+ surface: 'oklch(1 0 0)',
114
+ border: 'oklch(0.90 0.008 247.8)',
115
+ primaryAccent: 'oklch(0.55 0.22 265)',
116
+ textPrimary: 'oklch(0.20 0.02 265)',
117
+ textMuted: 'oklch(0.50 0.02 265)',
118
+ ring: 'oklch(0.55 0.22 265)',
119
+ },
120
+ typography: {
121
+ display: 'Inter, system-ui, sans-serif',
122
+ body: 'Inter, system-ui, sans-serif',
123
+ mono: 'Fira Code, monospace',
124
+ },
125
+ physics: {
126
+ springStiffness: 320,
127
+ dampingRatio: 0.88,
128
+ lerpAlpha: '1 - Math.exp(-16 * dt)',
129
+ },
130
+ },
131
+ };
132
+ /** Easing curves adhering to Vibe UI motion standards */
133
+ exports.MOTION_CURVES = {
134
+ naturalSpring: 'cubic-bezier(0.16, 1, 0.3, 1)',
135
+ responsiveSnap: 'cubic-bezier(0.25, 1, 0.5, 1)',
136
+ crispEnter: 'cubic-bezier(0, 0, 0.2, 1)',
137
+ crispExit: 'cubic-bezier(0.4, 0, 1, 1)',
138
+ };
139
+ /** Relative luminance formula conforming to WCAG 2.2 */
140
+ function getRelativeLuminance(r, g, b) {
141
+ const transform = (c) => {
142
+ const s = c / 255;
143
+ return s <= 0.04045 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
144
+ };
145
+ return 0.2126 * transform(r) + 0.7152 * transform(g) + 0.0722 * transform(b);
146
+ }
147
+ /** Contrast ratio between two luminance values */
148
+ function getContrastRatio(lumA, lumB) {
149
+ const l1 = Math.max(lumA, lumB);
150
+ const l2 = Math.min(lumA, lumB);
151
+ return (l1 + 0.05) / (l2 + 0.05);
152
+ }
package/dist/index.mjs ADDED
@@ -0,0 +1,147 @@
1
+ /**
2
+ * @vibe-ui/tokens
3
+ * Typed OKLCH design tokens, physics curves, and contrast utilities.
4
+ */
5
+ export const VISUAL_CHEMISTRIES = {
6
+ MINIMALIST_SAAS: {
7
+ id: 'MINIMALIST_SAAS',
8
+ name: 'Minimalist SaaS',
9
+ tagline: 'High-signal B2B productivity with subtle borders and monochrome restraint',
10
+ colors: {
11
+ canvas: 'oklch(0.14 0.005 264)',
12
+ surface: 'oklch(0.18 0.008 264)',
13
+ border: 'oklch(0.28 0.01 264)',
14
+ primaryAccent: 'oklch(0.65 0.22 260)',
15
+ textPrimary: 'oklch(0.98 0.002 264)',
16
+ textMuted: 'oklch(0.65 0.015 264)',
17
+ ring: 'oklch(0.65 0.22 260)',
18
+ },
19
+ typography: {
20
+ display: 'Inter, system-ui, sans-serif',
21
+ body: 'Inter, system-ui, sans-serif',
22
+ mono: 'JetBrains Mono, Menlo, monospace',
23
+ },
24
+ physics: {
25
+ springStiffness: 280,
26
+ dampingRatio: 0.85,
27
+ lerpAlpha: '1 - Math.exp(-14 * dt)',
28
+ },
29
+ },
30
+ LUXURY_GLASS_2: {
31
+ id: 'LUXURY_GLASS_2',
32
+ name: 'Luxury Glassmorphism 2.0',
33
+ tagline: 'Deep dark substrates with specular highlights and gold accents',
34
+ colors: {
35
+ canvas: 'oklch(0.12 0.015 280)',
36
+ surface: 'oklch(0.18 0.02 280 / 0.75)',
37
+ border: 'oklch(0.75 0.15 85 / 0.35)',
38
+ primaryAccent: 'oklch(0.78 0.16 85)',
39
+ textPrimary: 'oklch(0.98 0.005 85)',
40
+ textMuted: 'oklch(0.70 0.03 85)',
41
+ ring: 'oklch(0.78 0.16 85)',
42
+ },
43
+ typography: {
44
+ display: 'Cinzel, Playfair Display, serif',
45
+ body: 'Plus Jakarta Sans, sans-serif',
46
+ mono: 'JetBrains Mono, monospace',
47
+ },
48
+ physics: {
49
+ springStiffness: 180,
50
+ dampingRatio: 0.92,
51
+ lerpAlpha: '1 - Math.exp(-8 * dt)',
52
+ },
53
+ },
54
+ NEOBRUTALISM: {
55
+ id: 'NEOBRUTALISM',
56
+ name: 'Neobrutalism',
57
+ tagline: 'High-contrast saturated flat cards with hard 3px black offset shadows',
58
+ colors: {
59
+ canvas: 'oklch(0.96 0.01 95)',
60
+ surface: 'oklch(0.99 0.002 95)',
61
+ border: 'oklch(0.15 0.01 95)',
62
+ primaryAccent: 'oklch(0.82 0.20 135)',
63
+ textPrimary: 'oklch(0.12 0.01 95)',
64
+ textMuted: 'oklch(0.35 0.02 95)',
65
+ ring: 'oklch(0.15 0.01 95)',
66
+ },
67
+ typography: {
68
+ display: 'Space Grotesk, Syne, sans-serif',
69
+ body: 'Space Grotesk, sans-serif',
70
+ mono: 'Space Mono, monospace',
71
+ },
72
+ physics: {
73
+ springStiffness: 450,
74
+ dampingRatio: 0.7,
75
+ lerpAlpha: '1 - Math.exp(-22 * dt)',
76
+ },
77
+ },
78
+ SWISS_EDITORIAL: {
79
+ id: 'SWISS_EDITORIAL',
80
+ name: 'Swiss Editorial',
81
+ tagline: 'Asymmetric typography-first layout inspired by International Typographic Style',
82
+ colors: {
83
+ canvas: 'oklch(0.97 0.005 80)',
84
+ surface: 'oklch(0.93 0.008 80)',
85
+ border: 'oklch(0.20 0.005 80)',
86
+ primaryAccent: 'oklch(0.58 0.24 28)',
87
+ textPrimary: 'oklch(0.15 0.005 80)',
88
+ textMuted: 'oklch(0.42 0.01 80)',
89
+ ring: 'oklch(0.58 0.24 28)',
90
+ },
91
+ typography: {
92
+ display: 'Helvetica Neue, Arial, sans-serif',
93
+ body: 'Newsreader, Georgia, serif',
94
+ mono: 'Courier New, monospace',
95
+ },
96
+ physics: {
97
+ springStiffness: 300,
98
+ dampingRatio: 0.9,
99
+ lerpAlpha: '1 - Math.exp(-12 * dt)',
100
+ },
101
+ },
102
+ STRIPE_CRISP_LIGHT: {
103
+ id: 'STRIPE_CRISP_LIGHT',
104
+ name: 'Stripe Crisp Light',
105
+ tagline: 'Ultra-clean developer-first documentation layout with refined micro-borders',
106
+ colors: {
107
+ canvas: 'oklch(0.985 0.002 247.8)',
108
+ surface: 'oklch(1 0 0)',
109
+ border: 'oklch(0.90 0.008 247.8)',
110
+ primaryAccent: 'oklch(0.55 0.22 265)',
111
+ textPrimary: 'oklch(0.20 0.02 265)',
112
+ textMuted: 'oklch(0.50 0.02 265)',
113
+ ring: 'oklch(0.55 0.22 265)',
114
+ },
115
+ typography: {
116
+ display: 'Inter, system-ui, sans-serif',
117
+ body: 'Inter, system-ui, sans-serif',
118
+ mono: 'Fira Code, monospace',
119
+ },
120
+ physics: {
121
+ springStiffness: 320,
122
+ dampingRatio: 0.88,
123
+ lerpAlpha: '1 - Math.exp(-16 * dt)',
124
+ },
125
+ },
126
+ };
127
+ /** Easing curves adhering to Vibe UI motion standards */
128
+ export const MOTION_CURVES = {
129
+ naturalSpring: 'cubic-bezier(0.16, 1, 0.3, 1)',
130
+ responsiveSnap: 'cubic-bezier(0.25, 1, 0.5, 1)',
131
+ crispEnter: 'cubic-bezier(0, 0, 0.2, 1)',
132
+ crispExit: 'cubic-bezier(0.4, 0, 1, 1)',
133
+ };
134
+ /** Relative luminance formula conforming to WCAG 2.2 */
135
+ export function getRelativeLuminance(r, g, b) {
136
+ const transform = (c) => {
137
+ const s = c / 255;
138
+ return s <= 0.04045 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
139
+ };
140
+ return 0.2126 * transform(r) + 0.7152 * transform(g) + 0.0722 * transform(b);
141
+ }
142
+ /** Contrast ratio between two luminance values */
143
+ export function getContrastRatio(lumA, lumB) {
144
+ const l1 = Math.max(lumA, lumB);
145
+ const l2 = Math.min(lumA, lumB);
146
+ return (l1 + 0.05) / (l2 + 0.05);
147
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Vibe UI Component Registry
3
+ * Production-ready, accessible, AI-native React component templates.
4
+ */
5
+ export interface ComponentTemplate {
6
+ name: string;
7
+ filename: string;
8
+ description: string;
9
+ code: string;
10
+ }
11
+ export declare const COMPONENT_REGISTRY: Record<string, ComponentTemplate>;