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/README.md +151 -0
- package/build.js +23 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +278 -0
- package/dist/cli.mjs +243 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.js +152 -0
- package/dist/index.mjs +147 -0
- package/dist/registry/components.d.ts +11 -0
- package/dist/registry/components.js +223 -0
- package/dist/registry/components.mjs +220 -0
- package/dist/tailwind.d.ts +11 -0
- package/dist/tailwind.js +54 -0
- package/dist/tailwind.mjs +50 -0
- package/dist/v4.css +39 -0
- package/package.json +58 -0
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
|
+
});
|
package/dist/index.d.ts
ADDED
|
@@ -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>;
|