@webmate-studio/builder 0.2.136 → 0.2.139

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webmate-studio/builder",
3
- "version": "0.2.136",
3
+ "version": "0.2.139",
4
4
  "type": "module",
5
5
  "description": "Webmate Studio Component Builder",
6
6
  "keywords": [
@@ -8,79 +8,118 @@
8
8
  * Dokumentation: webmate-studio/docs/DESIGN-TOKEN-SCHEMA-V2.md
9
9
  */
10
10
 
11
- // ─── Farbskala-Generierung ──────────────────────────────────────────────────
11
+ // ─── OKLCH-Farbskala-Generierung ────────────────────────────────────────────
12
12
 
13
13
  /**
14
- * Generiert eine 12-Stufen-Farbskala aus einer Basisfarbe.
14
+ * Preset-Kurven für die Chroma-Verteilung über die 12 Stufen.
15
+ * stdDev = Breite der Gaußkurve (wie weit Sättigung von der Base ausstrahlt)
16
+ * chromaScale = globaler Sättigungsmultiplikator
17
+ */
18
+ export const COLOR_SCALE_PRESETS = {
19
+ vivid: { label: 'Leuchtend', stdDev: 40, chromaScale: 1.15 },
20
+ natural: { label: 'Natürlich', stdDev: 30, chromaScale: 1.0 },
21
+ soft: { label: 'Pastellig', stdDev: 16, chromaScale: 0.75 },
22
+ muted: { label: 'Gedämpft', stdDev: 22, chromaScale: 0.55 },
23
+ };
24
+
25
+ /**
26
+ * Generiert eine 12-Stufen-Farbskala aus einer Basisfarbe im OKLCH-Farbraum.
15
27
  * Stufe 9 = Basisfarbe. Stufen 1-8 heller, 10-12 dunkler.
16
28
  *
17
- * Für Neutral-Töne (niedrige Sättigung) wird die Sättigung automatisch
18
- * stark gedämpft, damit echte Grautöne entstehen statt verfärbter Pastelltöne.
29
+ * Verwendet OKLCH für perceptuell gleichmäßige Helligkeitsverteilung
30
+ * garantiert monoton abnehmende Helligkeit von Stufe 1 bis 12.
31
+ *
32
+ * @param {string} baseHex - Basisfarbe als Hex-String
33
+ * @param {object} [curve] - Optionale Kurvenparameter: { preset: 'natural' } oder { preset: 'custom', stdDev, chromaScale }
19
34
  */
20
- export function generateColorScale(baseHex) {
21
- const rgb = hexToRgb(baseHex);
22
- if (!rgb) return null;
35
+ export function generateColorScale(baseHex, curve) {
36
+ const base = hexToOklch(baseHex);
37
+ if (!base) return null;
38
+
39
+ // Kurvenparameter bestimmen
40
+ const presetName = curve?.preset || 'natural';
41
+ const preset = COLOR_SCALE_PRESETS[presetName];
42
+ const stdDev = curve?.preset === 'custom' ? (curve.stdDev ?? 20) : (preset?.stdDev ?? 20);
43
+ const chromaScale = curve?.preset === 'custom' ? (curve.chromaScale ?? 0.85) : (preset?.chromaScale ?? 0.85);
44
+
45
+ // Neutral-Erkennung: Basis mit sehr niedriger Chroma (reines Grau)
46
+ const isPureNeutral = base.c < 0.008;
47
+
48
+ // Lightness-Rampe adaptiv an Base-Lightness
49
+ const L = buildLightnessRamp(base.l);
50
+
51
+ // Wurde die Base-Lightness geclampt? (extrem helle/dunkle Farben)
52
+ const baseClamped = Math.abs(L[8] - base.l) > 0.01;
53
+
54
+ const scale = {};
55
+ for (let i = 0; i < 12; i++) {
56
+ const step = i + 1;
57
+ if (step === 9 && !baseClamped) {
58
+ // Step 9 = exakte Base-Farbe (wenn nicht geclampt)
59
+ scale[step] = baseHex;
60
+ continue;
61
+ }
23
62
 
24
- const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b);
25
- const h = hsl.h;
26
- const s = hsl.s;
27
- const l = hsl.l;
63
+ // Chroma über Gaußkurve berechnen
64
+ let c;
65
+ if (isPureNeutral) {
66
+ // Reines Grau: minimale Chroma, Step 1 wird weiß
67
+ c = base.c * 0.3;
68
+ } else if (step === 9) {
69
+ // Geclampt: volle Base-Chroma bei korrigierter Lightness
70
+ c = base.c;
71
+ } else {
72
+ c = computeChroma(L[i], L[8], base.c, stdDev, chromaScale);
73
+ }
28
74
 
29
- // Neutral-Erkennung: Basis mit niedriger Sättigung (<15%)
30
- const isNeutral = s < 15;
31
- const sFactor = isNeutral ? 0.15 : 1;
32
- // Helle Stufen: leichter Hue-Shift für natürlichere Farbverläufe
33
- const hShift = isNeutral ? 0 : -5;
75
+ const mapped = gamutMapOklch(L[i], c, base.h);
76
+ scale[step] = oklchToHex(mapped.l, mapped.c, mapped.h);
77
+ }
34
78
 
35
- return {
36
- 1: isNeutral ? '#ffffff' : hslToHex(h + hShift, Math.min(s * 0.85, 70), 99),
37
- 2: hslToHex(h + hShift, Math.min(s * 0.65 * sFactor, isNeutral ? 4 : 55), 97),
38
- 3: hslToHex(h + hShift, Math.min(s * 0.72 * sFactor, isNeutral ? 5 : 60), 94),
39
- 4: hslToHex(h + hShift, Math.min(s * 0.7 * sFactor, isNeutral ? 5 : 58), 89),
40
- 5: hslToHex(h + hShift, Math.min(s * 0.68 * sFactor, isNeutral ? 5 : 55), 84),
41
- 6: hslToHex(h - 2, Math.min(s * 0.63 * sFactor, isNeutral ? 5 : 52), 77),
42
- 7: hslToHex(h - 1, Math.min(s * 0.6 * sFactor, isNeutral ? 5 : 50), 68),
43
- 8: hslToHex(h, Math.min(s * 0.62 * sFactor, isNeutral ? 6 : 50), 53),
44
- 9: baseHex,
45
- 10: hslToHex(h + 2, Math.min(s * 1.3 * sFactor, isNeutral ? 8 : 100), Math.max(l - 7, 15)),
46
- 11: hslToHex(h + 1, Math.min(s * 1.3 * sFactor, isNeutral ? 6 : 100), Math.max(l - 11, 20)),
47
- 12: hslToHex(h - 5, Math.min(s * 0.55 * sFactor, isNeutral ? 4 : 45), isNeutral ? 13 : Math.max(l * 0.5, 15)),
48
- };
79
+ // Reines Neutral Step 1 = reines Weiß
80
+ if (isPureNeutral) {
81
+ scale[1] = '#ffffff';
82
+ }
83
+
84
+ return scale;
49
85
  }
50
86
 
51
87
  /**
52
- * Generiert eine invertierte 12-Stufen-Skala für Dark Mode.
88
+ * Generiert eine invertierte 12-Stufen-Skala für Dark Mode im OKLCH-Farbraum.
53
89
  * Stufe 1 = dunkelster Wert, Stufe 12 = hellster.
54
90
  */
55
- export function generateDarkColorScale(baseHex) {
56
- const rgb = hexToRgb(baseHex);
57
- if (!rgb) return null;
58
-
59
- const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b);
60
- const h = hsl.h;
61
- const s = hsl.s;
62
- const l = hsl.l;
63
-
64
- const isNeutral = s < 15;
65
- const sFactor = isNeutral ? 0.15 : 1;
91
+ export function generateDarkColorScale(baseHex, curve) {
92
+ const base = hexToOklch(baseHex);
93
+ if (!base) return null;
94
+
95
+ const presetName = curve?.preset || 'natural';
96
+ const preset = COLOR_SCALE_PRESETS[presetName];
97
+ const stdDev = curve?.preset === 'custom' ? (curve.stdDev ?? 20) : (preset?.stdDev ?? 20);
98
+ const chromaScale = curve?.preset === 'custom' ? (curve.chromaScale ?? 0.85) : (preset?.chromaScale ?? 0.85);
99
+
100
+ const isPureNeutral = base.c < 0.008;
101
+
102
+ // Dark Mode: Base etwas heller für bessere Sichtbarkeit
103
+ const darkBaseL = Math.min(base.l + 0.08, 0.65);
104
+
105
+ // Lightness-Rampe adaptiv (invertiert für Dark Mode)
106
+ const L = buildDarkLightnessRamp(darkBaseL);
107
+
108
+ const scale = {};
109
+ for (let i = 0; i < 12; i++) {
110
+ const step = i + 1;
111
+ let c;
112
+ if (isPureNeutral) {
113
+ c = base.c * 0.3;
114
+ } else {
115
+ c = computeChroma(L[i], L[8], base.c, stdDev, chromaScale);
116
+ }
66
117
 
67
- // Dark Mode: Basis etwas heller für bessere Sichtbarkeit
68
- const darkBase = hslToHex(h, Math.min(s * 1.1 * sFactor, isNeutral ? 8 : 100), Math.min(l + 10, 65));
118
+ const mapped = gamutMapOklch(L[i], c, base.h);
119
+ scale[step] = oklchToHex(mapped.l, mapped.c, mapped.h);
120
+ }
69
121
 
70
- return {
71
- 1: hslToHex(h, Math.min(s * 0.35 * sFactor, isNeutral ? 2 : 15), 8),
72
- 2: hslToHex(h, Math.min(s * 0.4 * sFactor, isNeutral ? 3 : 18), 12),
73
- 3: hslToHex(h, Math.min(s * 0.5 * sFactor, isNeutral ? 4 : 22), 18),
74
- 4: hslToHex(h, Math.min(s * 0.55 * sFactor, isNeutral ? 4 : 28), 24),
75
- 5: hslToHex(h, Math.min(s * 0.6 * sFactor, isNeutral ? 5 : 32), 30),
76
- 6: hslToHex(h - 2, Math.min(s * 0.63 * sFactor, isNeutral ? 5 : 40), 38),
77
- 7: hslToHex(h - 1, Math.min(s * 0.7 * sFactor, isNeutral ? 5 : 48), 48),
78
- 8: hslToHex(h, Math.min(s * 0.8 * sFactor, isNeutral ? 6 : 55), 58),
79
- 9: darkBase,
80
- 10: hslToHex(h + 1, Math.min(s * 0.85 * sFactor, isNeutral ? 6 : 65), Math.min(l + 20, 75)),
81
- 11: hslToHex(h + 2, Math.min(s * 0.6 * sFactor, isNeutral ? 5 : 50), Math.min(l + 35, 85)),
82
- 12: hslToHex(h - 3, Math.min(s * 0.35 * sFactor, isNeutral ? 3 : 30), Math.min(l + 50, 95)),
83
- };
122
+ return scale;
84
123
  }
85
124
 
86
125
  /**
@@ -171,6 +210,286 @@ function hslToHex(h, s, l) {
171
210
  return rgbToHex((r + m) * 255, (g + m) * 255, (b + m) * 255);
172
211
  }
173
212
 
213
+ // ─── OKLCH-Hilfsfunktionen ──────────────────────────────────────────────────
214
+
215
+ /**
216
+ * Baut eine strikt monoton fallende Lightness-Rampe für 12 Stufen.
217
+ * Steps 1-8 werden zwischen topL und baseL verteilt (Ease-Out-Kurve).
218
+ * Steps 10-12 werden zwischen baseL und bottomL verteilt.
219
+ * Step 9 = baseL (exakt).
220
+ *
221
+ * Funktioniert auch bei extremen Base-Werten (sehr hell/dunkel):
222
+ * - Die Rampe wird auf den verfügbaren Bereich komprimiert
223
+ * - Monotonie ist durch die Konstruktion garantiert
224
+ */
225
+ function buildLightnessRamp(baseL) {
226
+ const topL = 0.985; // Step 1: fast Weiß
227
+ const bottomL = 0.25; // Step 12: dunkelster Wert
228
+
229
+ // Base clampen: min. 0.30 damit 3 dunkle Stufen Platz haben,
230
+ // max. 0.80 damit 8 helle Stufen genug Abstand in sRGB haben
231
+ const safeBaseL = Math.max(0.30, Math.min(0.80, baseL));
232
+
233
+ // Steps 1-8: Von topL nach safeBaseL + Lücke
234
+ // Die Lücke stellt sicher, dass Step 8 immer heller als Step 9 ist
235
+ const gap = Math.max(0.02, (topL - safeBaseL) * 0.05);
236
+ const step8Target = safeBaseL + gap;
237
+ const range = topL - step8Target;
238
+
239
+ // Feste Verteilungs-Gewichte: Steps 1-2 bleiben nahe Weiß,
240
+ // dann beschleunigter Abstieg zur Base. Inspiriert von Radix' Lightness-Verteilung.
241
+ const weights = [0.0, 0.04, 0.10, 0.20, 0.34, 0.50, 0.70, 0.92];
242
+ const lightSteps = weights.map(w => topL - w * range);
243
+
244
+ // Steps 10-12: nach unten von Base weg
245
+ const darkRange = safeBaseL - bottomL;
246
+ const step10L = safeBaseL - darkRange * 0.12;
247
+ const step11L = safeBaseL - darkRange * 0.55;
248
+ const step12L = bottomL;
249
+
250
+ const ramp = [
251
+ ...lightSteps, // Steps 1-8
252
+ safeBaseL, // Step 9
253
+ step10L, // Step 10
254
+ step11L, // Step 11
255
+ step12L, // Step 12
256
+ ];
257
+
258
+ // Finale Sicherheit: strikt monoton fallend
259
+ for (let i = 1; i < ramp.length; i++) {
260
+ if (ramp[i] >= ramp[i - 1]) {
261
+ ramp[i] = ramp[i - 1] - 0.003;
262
+ }
263
+ }
264
+
265
+ return ramp;
266
+ }
267
+
268
+ /**
269
+ * Baut eine strikt monoton steigende Lightness-Rampe für Dark Mode.
270
+ * Steps 1-8: dunkel → darkBaseL, Steps 10-12: darkBaseL → hell.
271
+ */
272
+ function buildDarkLightnessRamp(darkBaseL) {
273
+ const bottomL = 0.14;
274
+ const topL = 0.94;
275
+
276
+ const safeBaseL = Math.max(0.22, Math.min(0.85, darkBaseL));
277
+
278
+ const gap = Math.max(0.02, (safeBaseL - bottomL) * 0.05);
279
+ const step8Target = safeBaseL - gap;
280
+ const range = step8Target - bottomL;
281
+
282
+ const weights = [0.0, 0.04, 0.10, 0.20, 0.34, 0.50, 0.70, 0.92];
283
+ const darkSteps = weights.map(w => bottomL + w * range);
284
+
285
+ const lightRange = topL - safeBaseL;
286
+ const step10L = safeBaseL + lightRange * 0.15;
287
+ const step11L = safeBaseL + lightRange * 0.55;
288
+ const step12L = topL;
289
+
290
+ const ramp = [
291
+ ...darkSteps,
292
+ safeBaseL,
293
+ step10L,
294
+ step11L,
295
+ step12L,
296
+ ];
297
+
298
+ for (let i = 1; i < ramp.length; i++) {
299
+ if (ramp[i] <= ramp[i - 1]) {
300
+ ramp[i] = ramp[i - 1] + 0.003;
301
+ }
302
+ }
303
+
304
+ return ramp;
305
+ }
306
+
307
+ /**
308
+ * Chroma-Berechnung für eine Stufe: Gaußkurve × Lightness-Begrenzung.
309
+ *
310
+ * Die Gaußkurve bestimmt den gewünschten Chroma-Anteil basierend auf der
311
+ * Distanz zur Base-Lightness. Zusätzlich wird die Chroma durch einen
312
+ * Lightness-Faktor begrenzt: Je näher an Weiß (L=1) oder Schwarz (L=0),
313
+ * desto weniger Chroma ist physisch/visuell sinnvoll.
314
+ *
315
+ * Das sorgt dafür, dass Steps 1-2 fast weiß und Steps 11-12 fast schwarz
316
+ * sind — wie bei Radix Colors.
317
+ */
318
+ function computeChroma(stepL, baseL, baseC, stdDev, chromaScale) {
319
+ // Gaußkurve: Peak bei baseL, flachere Flanken als vorher
320
+ const diff = baseL - stepL;
321
+ const gaussian = Math.exp((-12 / stdDev) * diff * diff);
322
+
323
+ // Lightness-Begrenzung: Asymmetrisch
324
+ // Helle Seite (L > 0.85): Chroma fällt steil auf 0 → Steps 1-2 bleiben fast weiß
325
+ // Dunkle Seite (L < 0.3): Chroma fällt moderat → Steps 11-12 behalten Farbton
326
+ // Mitte (0.3-0.85): Nahezu volle Chroma möglich
327
+ let lightnessLimit;
328
+ if (stepL > 0.85) {
329
+ // Steep falloff for near-white steps
330
+ const t = (stepL - 0.85) / 0.15; // 0 at L=0.85, 1 at L=1.0
331
+ lightnessLimit = 1.0 - t * t; // quadratic drop
332
+ } else if (stepL < 0.3) {
333
+ // Moderate falloff for near-black steps
334
+ const t = stepL / 0.3; // 0 at L=0, 1 at L=0.3
335
+ lightnessLimit = t * t; // quadratic rise
336
+ } else {
337
+ lightnessLimit = 1.0;
338
+ }
339
+
340
+ return baseC * gaussian * lightnessLimit * chromaScale;
341
+ }
342
+
343
+
344
+ /**
345
+ * Hex → OKLCH Konvertierung.
346
+ * Pfad: Hex → sRGB → Linear RGB → OKLab → OKLCH
347
+ */
348
+ function hexToOklch(hex) {
349
+ const rgb = hexToRgb(hex);
350
+ if (!rgb) return null;
351
+
352
+ // sRGB → Linear RGB (Gamma-Dekodierung)
353
+ const lr = srgbToLinear(rgb.r / 255);
354
+ const lg = srgbToLinear(rgb.g / 255);
355
+ const lb = srgbToLinear(rgb.b / 255);
356
+
357
+ // Linear RGB → OKLab
358
+ const lab = linearRgbToOklab(lr, lg, lb);
359
+
360
+ // OKLab → OKLCH
361
+ const c = Math.sqrt(lab.a * lab.a + lab.b * lab.b);
362
+ let h = Math.atan2(lab.b, lab.a) * 180 / Math.PI;
363
+ if (h < 0) h += 360;
364
+
365
+ return { l: lab.l, c, h };
366
+ }
367
+
368
+ /**
369
+ * OKLCH → Hex Konvertierung.
370
+ * Pfad: OKLCH → OKLab → Linear RGB → sRGB → Hex
371
+ */
372
+ function oklchToHex(l, c, h) {
373
+ // OKLCH → OKLab
374
+ const hRad = h * Math.PI / 180;
375
+ const a = c * Math.cos(hRad);
376
+ const b = c * Math.sin(hRad);
377
+
378
+ // OKLab → Linear RGB
379
+ const lin = oklabToLinearRgb(l, a, b);
380
+
381
+ // Linear RGB → sRGB (Gamma-Kodierung)
382
+ const sr = Math.round(linearToSrgb(lin.r) * 255);
383
+ const sg = Math.round(linearToSrgb(lin.g) * 255);
384
+ const sb = Math.round(linearToSrgb(lin.b) * 255);
385
+
386
+ return rgbToHex(
387
+ Math.max(0, Math.min(255, sr)),
388
+ Math.max(0, Math.min(255, sg)),
389
+ Math.max(0, Math.min(255, sb))
390
+ );
391
+ }
392
+
393
+ /**
394
+ * Gamut-Mapping: Reduziert Chroma bis die Farbe in sRGB darstellbar ist.
395
+ * Behält Lightness und Hue bei.
396
+ */
397
+ function gamutMapOklch(l, c, h) {
398
+ // Triviale Fälle
399
+ if (c <= 0) return { l, c: 0, h };
400
+ if (isInSrgbGamut(l, c, h)) return { l, c, h };
401
+
402
+ // Binary Search: Chroma reduzieren
403
+ let low = 0;
404
+ let high = c;
405
+ for (let i = 0; i < 20; i++) {
406
+ const mid = (low + high) / 2;
407
+ if (isInSrgbGamut(l, mid, h)) {
408
+ low = mid;
409
+ } else {
410
+ high = mid;
411
+ }
412
+ }
413
+ return { l, c: low, h };
414
+ }
415
+
416
+ /**
417
+ * Prüft ob eine OKLCH-Farbe innerhalb des sRGB-Gamuts liegt.
418
+ */
419
+ function isInSrgbGamut(l, c, h) {
420
+ const hRad = h * Math.PI / 180;
421
+ const a = c * Math.cos(hRad);
422
+ const b = c * Math.sin(hRad);
423
+ const lin = oklabToLinearRgb(l, a, b);
424
+ const eps = -0.001; // Kleine Toleranz für Rundungsfehler
425
+ return lin.r >= eps && lin.r <= 1.001 &&
426
+ lin.g >= eps && lin.g <= 1.001 &&
427
+ lin.b >= eps && lin.b <= 1.001;
428
+ }
429
+
430
+ /**
431
+ * Linear RGB → OKLab (Bjorn Ottosson, 2020)
432
+ */
433
+ function linearRgbToOklab(r, g, b) {
434
+ // Linear RGB → LMS (via M1 Matrix)
435
+ const l_ = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
436
+ const m_ = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
437
+ const s_ = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
438
+
439
+ // Kubikwurzel
440
+ const l = Math.cbrt(l_);
441
+ const m = Math.cbrt(m_);
442
+ const s = Math.cbrt(s_);
443
+
444
+ // LMS → OKLab (via M2 Matrix)
445
+ return {
446
+ l: 0.2104542553 * l + 0.7936177850 * m - 0.0040720468 * s,
447
+ a: 1.9779984951 * l - 2.4285922050 * m + 0.4505937099 * s,
448
+ b: 0.0259040371 * l + 0.7827717662 * m - 0.8086757660 * s,
449
+ };
450
+ }
451
+
452
+ /**
453
+ * OKLab → Linear RGB (Inverse von linearRgbToOklab)
454
+ */
455
+ function oklabToLinearRgb(L, a, b) {
456
+ // OKLab → LMS (inverse M2)
457
+ const l = L + 0.3963377774 * a + 0.2158037573 * b;
458
+ const m = L - 0.1055613458 * a - 0.0638541728 * b;
459
+ const s = L - 0.0894841775 * a - 1.2914855480 * b;
460
+
461
+ // LMS kubisch
462
+ const l3 = l * l * l;
463
+ const m3 = m * m * m;
464
+ const s3 = s * s * s;
465
+
466
+ // LMS → Linear RGB (inverse M1)
467
+ return {
468
+ r: 4.0767416621 * l3 - 3.3077115913 * m3 + 0.2309699292 * s3,
469
+ g: -1.2684380046 * l3 + 2.6097574011 * m3 - 0.3413193965 * s3,
470
+ b: -0.0041960863 * l3 - 0.7034186147 * m3 + 1.7076147010 * s3,
471
+ };
472
+ }
473
+
474
+ /**
475
+ * sRGB Gamma-Dekodierung (sRGB → Linear)
476
+ */
477
+ function srgbToLinear(c) {
478
+ return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
479
+ }
480
+
481
+ /**
482
+ * sRGB Gamma-Kodierung (Linear → sRGB)
483
+ */
484
+ function linearToSrgb(c) {
485
+ if (c <= 0) return 0;
486
+ if (c >= 1) return 1;
487
+ return c <= 0.0031308 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
488
+ }
489
+
490
+
491
+ // ─── Legacy Farb-Hilfsfunktionen (HSL, Luminanz) ───────────────────────────
492
+
174
493
  function relativeLuminance(r, g, b) {
175
494
  const [rs, gs, bs] = [r, g, b].map(c => {
176
495
  c = c / 255;
@@ -193,6 +512,8 @@ function contrastRatio(l1, l2) {
193
512
  * Brand-Welten (primary, secondary, accent) + Status-Welten (success, warning, error, info) + Neutral.
194
513
  */
195
514
  export const COLOR_WORLDS = ['primary', 'secondary', 'accent', 'success', 'warning', 'error', 'info', 'neutral'];
515
+ export const BRAND_COLOR_WORLDS = ['primary', 'secondary', 'accent', 'neutral'];
516
+ export const STATUS_COLOR_WORLDS = ['success', 'warning', 'error', 'info'];
196
517
  export const SEMANTIC_COLOR_WORLDS = ['primary', 'secondary', 'accent', 'success', 'warning', 'error', 'info'];
197
518
 
198
519
  /**
@@ -302,34 +623,42 @@ export const defaultDesignTokensV2 = {
302
623
  colors: {
303
624
  primary: {
304
625
  base: '#1E40AF',
626
+ curve: { preset: 'natural' },
305
627
  scale: generateColorScale('#1E40AF')
306
628
  },
307
629
  secondary: {
308
630
  base: '#6366F1',
631
+ curve: { preset: 'natural' },
309
632
  scale: generateColorScale('#6366F1')
310
633
  },
311
634
  accent: {
312
635
  base: '#8B5CF6',
636
+ curve: { preset: 'natural' },
313
637
  scale: generateColorScale('#8B5CF6')
314
638
  },
315
639
  success: {
316
640
  base: '#16A34A',
641
+ curve: { preset: 'natural' },
317
642
  scale: generateColorScale('#16A34A')
318
643
  },
319
644
  warning: {
320
645
  base: '#D97706',
646
+ curve: { preset: 'natural' },
321
647
  scale: generateColorScale('#D97706')
322
648
  },
323
649
  error: {
324
650
  base: '#DC2626',
651
+ curve: { preset: 'natural' },
325
652
  scale: generateColorScale('#DC2626')
326
653
  },
327
654
  info: {
328
655
  base: '#2563EB',
656
+ curve: { preset: 'natural' },
329
657
  scale: generateColorScale('#2563EB')
330
658
  },
331
659
  neutral: {
332
- base: '#6B7280', // Kühles Grau — gibt dem Design System seinen Charakter
660
+ base: '#6B7280',
661
+ curve: { preset: 'natural' },
333
662
  scale: generateColorScale('#6B7280')
334
663
  }
335
664
  },