@xivdyetools/svg 1.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 +136 -0
- package/dist/accessibility-comparison.d.ts +66 -0
- package/dist/accessibility-comparison.d.ts.map +1 -0
- package/dist/accessibility-comparison.js +201 -0
- package/dist/accessibility-comparison.js.map +1 -0
- package/dist/base.d.ts +115 -0
- package/dist/base.d.ts.map +1 -0
- package/dist/base.js +201 -0
- package/dist/base.js.map +1 -0
- package/dist/budget-comparison.d.ts +121 -0
- package/dist/budget-comparison.d.ts.map +1 -0
- package/dist/budget-comparison.js +331 -0
- package/dist/budget-comparison.js.map +1 -0
- package/dist/comparison-grid.d.ts +61 -0
- package/dist/comparison-grid.d.ts.map +1 -0
- package/dist/comparison-grid.js +366 -0
- package/dist/comparison-grid.js.map +1 -0
- package/dist/contrast-matrix.d.ts +78 -0
- package/dist/contrast-matrix.d.ts.map +1 -0
- package/dist/contrast-matrix.js +303 -0
- package/dist/contrast-matrix.js.map +1 -0
- package/dist/dye-info-card.d.ts +34 -0
- package/dist/dye-info-card.d.ts.map +1 -0
- package/dist/dye-info-card.js +218 -0
- package/dist/dye-info-card.js.map +1 -0
- package/dist/gradient.d.ts +49 -0
- package/dist/gradient.d.ts.map +1 -0
- package/dist/gradient.js +131 -0
- package/dist/gradient.js.map +1 -0
- package/dist/harmony-wheel.d.ts +38 -0
- package/dist/harmony-wheel.d.ts.map +1 -0
- package/dist/harmony-wheel.js +158 -0
- package/dist/harmony-wheel.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/palette-grid.d.ts +105 -0
- package/dist/palette-grid.d.ts.map +1 -0
- package/dist/palette-grid.js +277 -0
- package/dist/palette-grid.js.map +1 -0
- package/dist/preset-swatch.d.ts +76 -0
- package/dist/preset-swatch.d.ts.map +1 -0
- package/dist/preset-swatch.js +226 -0
- package/dist/preset-swatch.js.map +1 -0
- package/dist/random-dyes-grid.d.ts +45 -0
- package/dist/random-dyes-grid.d.ts.map +1 -0
- package/dist/random-dyes-grid.js +143 -0
- package/dist/random-dyes-grid.js.map +1 -0
- package/package.json +56 -0
package/dist/gradient.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gradient Bar SVG Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates a color gradient visualization showing steps between two colors
|
|
5
|
+
* with hex codes and matched dye names below each step.
|
|
6
|
+
*/
|
|
7
|
+
import { createSvgDocument, rect, line, text, getContrastTextColor, THEME, FONTS, } from './base.js';
|
|
8
|
+
/**
|
|
9
|
+
* Generates a gradient bar SVG showing color progression with dye matches
|
|
10
|
+
*/
|
|
11
|
+
export function generateGradientBar(options) {
|
|
12
|
+
const { steps, width = 800, height = 200, showTicks = true, showEndLabels = true, startLabel = 'START', endLabel = 'END', } = options;
|
|
13
|
+
if (steps.length < 2) {
|
|
14
|
+
throw new Error('Gradient requires at least 2 steps');
|
|
15
|
+
}
|
|
16
|
+
const elements = [];
|
|
17
|
+
// Layout constants
|
|
18
|
+
const padding = 20;
|
|
19
|
+
const barHeight = 60;
|
|
20
|
+
const barY = 40;
|
|
21
|
+
const hexLabelY = barY + barHeight + 20;
|
|
22
|
+
const nameLabelY = hexLabelY + 18;
|
|
23
|
+
const endLabelY = barY - 10;
|
|
24
|
+
const barWidth = width - padding * 2;
|
|
25
|
+
const stepWidth = barWidth / steps.length;
|
|
26
|
+
// Background
|
|
27
|
+
elements.push(rect(0, 0, width, height, THEME.background, { rx: 12 }));
|
|
28
|
+
// Draw each color step
|
|
29
|
+
steps.forEach((step, i) => {
|
|
30
|
+
const x = padding + i * stepWidth;
|
|
31
|
+
// Color rectangle
|
|
32
|
+
elements.push(rect(x, barY, stepWidth, barHeight, step.hex, {
|
|
33
|
+
stroke: i === 0 || i === steps.length - 1 ? '#ffffff' : undefined,
|
|
34
|
+
strokeWidth: i === 0 || i === steps.length - 1 ? 2 : undefined,
|
|
35
|
+
}));
|
|
36
|
+
// Hex label below the bar
|
|
37
|
+
const centerX = x + stepWidth / 2;
|
|
38
|
+
elements.push(text(centerX, hexLabelY, step.hex.toUpperCase(), {
|
|
39
|
+
fill: THEME.textMuted,
|
|
40
|
+
fontSize: 11,
|
|
41
|
+
fontFamily: FONTS.mono,
|
|
42
|
+
textAnchor: 'middle',
|
|
43
|
+
}));
|
|
44
|
+
// Dye name below hex (if available)
|
|
45
|
+
// Uses primaryCjk font for CJK language support (Japanese/Korean/Chinese dye names)
|
|
46
|
+
if (step.dyeName) {
|
|
47
|
+
const truncatedName = truncateName(step.dyeName, 12);
|
|
48
|
+
elements.push(text(centerX, nameLabelY, truncatedName, {
|
|
49
|
+
fill: THEME.text,
|
|
50
|
+
fontSize: 10,
|
|
51
|
+
fontFamily: FONTS.primaryCjk,
|
|
52
|
+
textAnchor: 'middle',
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
// Draw tick marks between steps
|
|
57
|
+
if (showTicks) {
|
|
58
|
+
for (let i = 1; i < steps.length; i++) {
|
|
59
|
+
const tickX = padding + i * stepWidth;
|
|
60
|
+
elements.push(line(tickX, barY - 5, tickX, barY, THEME.textDim, 1));
|
|
61
|
+
elements.push(line(tickX, barY + barHeight, tickX, barY + barHeight + 5, THEME.textDim, 1));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Draw START/END labels (localized)
|
|
65
|
+
// Uses primaryCjk font for CJK language support (e.g., 開始/終了 in Japanese)
|
|
66
|
+
if (showEndLabels) {
|
|
67
|
+
elements.push(text(padding + stepWidth / 2, endLabelY, startLabel, {
|
|
68
|
+
fill: THEME.textMuted,
|
|
69
|
+
fontSize: 10,
|
|
70
|
+
fontFamily: FONTS.primaryCjk,
|
|
71
|
+
textAnchor: 'middle',
|
|
72
|
+
fontWeight: 'bold',
|
|
73
|
+
}));
|
|
74
|
+
elements.push(text(padding + (steps.length - 0.5) * stepWidth, endLabelY, endLabel, {
|
|
75
|
+
fill: THEME.textMuted,
|
|
76
|
+
fontSize: 10,
|
|
77
|
+
fontFamily: FONTS.primaryCjk,
|
|
78
|
+
textAnchor: 'middle',
|
|
79
|
+
fontWeight: 'bold',
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
// Outer border around the gradient bar
|
|
83
|
+
elements.push(rect(padding, barY, barWidth, barHeight, 'none', {
|
|
84
|
+
stroke: THEME.border,
|
|
85
|
+
strokeWidth: 1,
|
|
86
|
+
}));
|
|
87
|
+
return createSvgDocument(width, height, elements.join('\n'));
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Truncates a name to fit within the step width
|
|
91
|
+
*/
|
|
92
|
+
function truncateName(name, maxLength) {
|
|
93
|
+
if (name.length <= maxLength)
|
|
94
|
+
return name;
|
|
95
|
+
return name.slice(0, maxLength - 2) + '..';
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Interpolates between two colors in RGB space
|
|
99
|
+
* @param color1 Starting hex color
|
|
100
|
+
* @param color2 Ending hex color
|
|
101
|
+
* @param ratio Interpolation ratio (0 = color1, 1 = color2)
|
|
102
|
+
*/
|
|
103
|
+
export function interpolateColor(color1, color2, ratio) {
|
|
104
|
+
const hex1 = color1.replace('#', '');
|
|
105
|
+
const hex2 = color2.replace('#', '');
|
|
106
|
+
const r1 = parseInt(hex1.slice(0, 2), 16);
|
|
107
|
+
const g1 = parseInt(hex1.slice(2, 4), 16);
|
|
108
|
+
const b1 = parseInt(hex1.slice(4, 6), 16);
|
|
109
|
+
const r2 = parseInt(hex2.slice(0, 2), 16);
|
|
110
|
+
const g2 = parseInt(hex2.slice(2, 4), 16);
|
|
111
|
+
const b2 = parseInt(hex2.slice(4, 6), 16);
|
|
112
|
+
const r = Math.round(r1 + (r2 - r1) * ratio);
|
|
113
|
+
const g = Math.round(g1 + (g2 - g1) * ratio);
|
|
114
|
+
const b = Math.round(b1 + (b2 - b1) * ratio);
|
|
115
|
+
return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Generates an array of interpolated colors between start and end
|
|
119
|
+
* @param startColor Starting hex color
|
|
120
|
+
* @param endColor Ending hex color
|
|
121
|
+
* @param stepCount Number of steps (including start and end)
|
|
122
|
+
*/
|
|
123
|
+
export function generateGradientColors(startColor, endColor, stepCount) {
|
|
124
|
+
const colors = [];
|
|
125
|
+
for (let i = 0; i < stepCount; i++) {
|
|
126
|
+
const ratio = i / (stepCount - 1);
|
|
127
|
+
colors.push(interpolateColor(startColor, endColor, ratio));
|
|
128
|
+
}
|
|
129
|
+
return colors;
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=gradient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gradient.js","sourceRoot":"","sources":["../src/gradient.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,iBAAiB,EACjB,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,oBAAoB,EACpB,KAAK,EACL,KAAK,GACN,MAAM,WAAW,CAAC;AA4BnB;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAA2B;IAC7D,MAAM,EACJ,KAAK,EACL,KAAK,GAAG,GAAG,EACX,MAAM,GAAG,GAAG,EACZ,SAAS,GAAG,IAAI,EAChB,aAAa,GAAG,IAAI,EACpB,UAAU,GAAG,OAAO,EACpB,QAAQ,GAAG,KAAK,GACjB,GAAG,OAAO,CAAC;IAEZ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,mBAAmB;IACnB,MAAM,OAAO,GAAG,EAAE,CAAC;IACnB,MAAM,SAAS,GAAG,EAAE,CAAC;IACrB,MAAM,IAAI,GAAG,EAAE,CAAC;IAChB,MAAM,SAAS,GAAG,IAAI,GAAG,SAAS,GAAG,EAAE,CAAC;IACxC,MAAM,UAAU,GAAG,SAAS,GAAG,EAAE,CAAC;IAClC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAE,CAAC;IAE5B,MAAM,QAAQ,GAAG,KAAK,GAAG,OAAO,GAAG,CAAC,CAAC;IACrC,MAAM,SAAS,GAAG,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC;IAE1C,aAAa;IACb,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,UAAU,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IAEvE,uBAAuB;IACvB,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;QACxB,MAAM,CAAC,GAAG,OAAO,GAAG,CAAC,GAAG,SAAS,CAAC;QAElC,kBAAkB;QAClB,QAAQ,CAAC,IAAI,CACX,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YAC5C,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;YACjE,WAAW,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;SAC/D,CAAC,CACH,CAAC;QAEF,0BAA0B;QAC1B,MAAM,OAAO,GAAG,CAAC,GAAG,SAAS,GAAG,CAAC,CAAC;QAClC,QAAQ,CAAC,IAAI,CACX,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE;YAC/C,IAAI,EAAE,KAAK,CAAC,SAAS;YACrB,QAAQ,EAAE,EAAE;YACZ,UAAU,EAAE,KAAK,CAAC,IAAI;YACtB,UAAU,EAAE,QAAQ;SACrB,CAAC,CACH,CAAC;QAEF,oCAAoC;QACpC,oFAAoF;QACpF,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,aAAa,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACrD,QAAQ,CAAC,IAAI,CACX,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE;gBACvC,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,QAAQ,EAAE,EAAE;gBACZ,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,UAAU,EAAE,QAAQ;aACrB,CAAC,CACH,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,gCAAgC;IAChC,IAAI,SAAS,EAAE,CAAC;QACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,MAAM,KAAK,GAAG,OAAO,GAAG,CAAC,GAAG,SAAS,CAAC;YACtC,QAAQ,CAAC,IAAI,CACX,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CACrD,CAAC;YACF,QAAQ,CAAC,IAAI,CACX,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,SAAS,EAAE,KAAK,EAAE,IAAI,GAAG,SAAS,GAAG,CAAC,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAC7E,CAAC;QACJ,CAAC;IACH,CAAC;IAED,oCAAoC;IACpC,0EAA0E;IAC1E,IAAI,aAAa,EAAE,CAAC;QAClB,QAAQ,CAAC,IAAI,CACX,IAAI,CAAC,OAAO,GAAG,SAAS,GAAG,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE;YACnD,IAAI,EAAE,KAAK,CAAC,SAAS;YACrB,QAAQ,EAAE,EAAE;YACZ,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,UAAU,EAAE,QAAQ;YACpB,UAAU,EAAE,MAAM;SACnB,CAAC,CACH,CAAC;QACF,QAAQ,CAAC,IAAI,CACX,IAAI,CAAC,OAAO,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE;YACpE,IAAI,EAAE,KAAK,CAAC,SAAS;YACrB,QAAQ,EAAE,EAAE;YACZ,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,UAAU,EAAE,QAAQ;YACpB,UAAU,EAAE,MAAM;SACnB,CAAC,CACH,CAAC;IACJ,CAAC;IAED,uCAAuC;IACvC,QAAQ,CAAC,IAAI,CACX,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE;QAC/C,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,WAAW,EAAE,CAAC;KACf,CAAC,CACH,CAAC;IAEF,OAAO,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,IAAY,EAAE,SAAiB;IACnD,IAAI,IAAI,CAAC,MAAM,IAAI,SAAS;QAAE,OAAO,IAAI,CAAC;IAC1C,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC;AAC7C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc,EAAE,MAAc,EAAE,KAAa;IAC5E,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAErC,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1C,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1C,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAE1C,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1C,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1C,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAE1C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC;IAC7C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC;IAC7C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC;IAE7C,OAAO,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AACnH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,UAAkB,EAClB,QAAgB,EAChB,SAAiB;IAEjB,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Harmony Wheel SVG Generator (v4 Style)
|
|
3
|
+
*
|
|
4
|
+
* Generates a modern color harmony wheel visualization matching the v4 web app design.
|
|
5
|
+
* Features:
|
|
6
|
+
* - Large center swatch showing the base color with glow effect
|
|
7
|
+
* - Smooth conic gradient ring for the color spectrum
|
|
8
|
+
* - Small colored dot nodes positioned on the ring
|
|
9
|
+
* - Dashed connection lines between harmony points
|
|
10
|
+
*
|
|
11
|
+
* Colors are positioned on the wheel based on their HSV hue value,
|
|
12
|
+
* matching the traditional color wheel representation.
|
|
13
|
+
*/
|
|
14
|
+
export interface HarmonyDye {
|
|
15
|
+
id: number;
|
|
16
|
+
name: string;
|
|
17
|
+
hex: string;
|
|
18
|
+
category?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface HarmonyWheelOptions {
|
|
21
|
+
/** Base color hex */
|
|
22
|
+
baseColor: string;
|
|
23
|
+
/** Name of the base color/dye */
|
|
24
|
+
baseName?: string;
|
|
25
|
+
/** Type of harmony (triadic, complementary, etc.) */
|
|
26
|
+
harmonyType: string;
|
|
27
|
+
/** Matched dyes for the harmony */
|
|
28
|
+
dyes: HarmonyDye[];
|
|
29
|
+
/** Width of the output image */
|
|
30
|
+
width?: number;
|
|
31
|
+
/** Height of the output image */
|
|
32
|
+
height?: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Generates a v4-style harmony wheel SVG
|
|
36
|
+
*/
|
|
37
|
+
export declare function generateHarmonyWheel(options: HarmonyWheelOptions): string;
|
|
38
|
+
//# sourceMappingURL=harmony-wheel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harmony-wheel.d.ts","sourceRoot":"","sources":["../src/harmony-wheel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AASH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,qBAAqB;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB,mCAAmC;IACnC,IAAI,EAAE,UAAU,EAAE,CAAC;IACnB,gCAAgC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAuCD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAkGzE"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Harmony Wheel SVG Generator (v4 Style)
|
|
3
|
+
*
|
|
4
|
+
* Generates a modern color harmony wheel visualization matching the v4 web app design.
|
|
5
|
+
* Features:
|
|
6
|
+
* - Large center swatch showing the base color with glow effect
|
|
7
|
+
* - Smooth conic gradient ring for the color spectrum
|
|
8
|
+
* - Small colored dot nodes positioned on the ring
|
|
9
|
+
* - Dashed connection lines between harmony points
|
|
10
|
+
*
|
|
11
|
+
* Colors are positioned on the wheel based on their HSV hue value,
|
|
12
|
+
* matching the traditional color wheel representation.
|
|
13
|
+
*/
|
|
14
|
+
import { createSvgDocument, rect, hexToRgb, THEME, } from './base.js';
|
|
15
|
+
/**
|
|
16
|
+
* Converts RGB to HSV and returns the hue (0-360)
|
|
17
|
+
*/
|
|
18
|
+
function rgbToHue(r, g, b) {
|
|
19
|
+
r /= 255;
|
|
20
|
+
g /= 255;
|
|
21
|
+
b /= 255;
|
|
22
|
+
const max = Math.max(r, g, b);
|
|
23
|
+
const min = Math.min(r, g, b);
|
|
24
|
+
const delta = max - min;
|
|
25
|
+
let hue = 0;
|
|
26
|
+
if (delta === 0) {
|
|
27
|
+
hue = 0; // Achromatic (gray)
|
|
28
|
+
}
|
|
29
|
+
else if (max === r) {
|
|
30
|
+
hue = 60 * (((g - b) / delta) % 6);
|
|
31
|
+
}
|
|
32
|
+
else if (max === g) {
|
|
33
|
+
hue = 60 * ((b - r) / delta + 2);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
hue = 60 * ((r - g) / delta + 4);
|
|
37
|
+
}
|
|
38
|
+
if (hue < 0)
|
|
39
|
+
hue += 360;
|
|
40
|
+
return hue;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Gets the hue angle from a hex color
|
|
44
|
+
*/
|
|
45
|
+
function getHueFromHex(hex) {
|
|
46
|
+
const { r, g, b } = hexToRgb(hex);
|
|
47
|
+
return rgbToHue(r, g, b);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Generates a v4-style harmony wheel SVG
|
|
51
|
+
*/
|
|
52
|
+
export function generateHarmonyWheel(options) {
|
|
53
|
+
const { baseColor, baseName, harmonyType, dyes, width = 400, height = 400, } = options;
|
|
54
|
+
const centerX = width / 2;
|
|
55
|
+
const centerY = height / 2;
|
|
56
|
+
const wheelRadius = Math.min(width, height) / 2 - 30;
|
|
57
|
+
// v4 style sizing
|
|
58
|
+
const innerRadiusRatio = 0.6; // Thinner ring
|
|
59
|
+
const nodeRadiusRatio = 0.8; // Where nodes sit on the ring
|
|
60
|
+
const centerSwatchRadius = wheelRadius * 0.4; // Large center swatch (v4 style: 120px equivalent)
|
|
61
|
+
const harmonyNodeRadius = 10; // Small nodes (v4 style: 14px)
|
|
62
|
+
const baseNodeRadius = 12; // Slightly larger for base (v4 style: 18px)
|
|
63
|
+
const elements = [];
|
|
64
|
+
// Background with rounded corners
|
|
65
|
+
elements.push(rect(0, 0, width, height, THEME.background, { rx: 16 }));
|
|
66
|
+
// Generate defs for glow filter and drop shadow
|
|
67
|
+
elements.push(`<defs>
|
|
68
|
+
<filter id="centerGlow" x="-50%" y="-50%" width="200%" height="200%">
|
|
69
|
+
<feGaussianBlur in="SourceGraphic" stdDeviation="20" result="blur"/>
|
|
70
|
+
<feColorMatrix in="blur" type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.4 0"/>
|
|
71
|
+
<feMerge>
|
|
72
|
+
<feMergeNode/>
|
|
73
|
+
<feMergeNode in="SourceGraphic"/>
|
|
74
|
+
</feMerge>
|
|
75
|
+
</filter>
|
|
76
|
+
<filter id="nodeShadow" x="-50%" y="-50%" width="200%" height="200%">
|
|
77
|
+
<feDropShadow dx="0" dy="2" stdDeviation="3" flood-opacity="0.5"/>
|
|
78
|
+
</filter>
|
|
79
|
+
</defs>`);
|
|
80
|
+
// Color wheel ring (v4 style: smoother gradient with reduced opacity)
|
|
81
|
+
elements.push(generateColorWheelRing(centerX, centerY, wheelRadius, innerRadiusRatio));
|
|
82
|
+
// Get base color hue for positioning
|
|
83
|
+
const baseHue = getHueFromHex(baseColor);
|
|
84
|
+
// Calculate positions for all nodes
|
|
85
|
+
const baseAngle = baseHue - 90; // -90 to start from top
|
|
86
|
+
const baseRad = (baseAngle * Math.PI) / 180;
|
|
87
|
+
const baseX = centerX + Math.cos(baseRad) * wheelRadius * nodeRadiusRatio;
|
|
88
|
+
const baseY = centerY + Math.sin(baseRad) * wheelRadius * nodeRadiusRatio;
|
|
89
|
+
// Draw dashed connection lines (v4 style)
|
|
90
|
+
// Line from center to base node
|
|
91
|
+
elements.push(createDashedLine(centerX, centerY, baseX, baseY, 'rgba(255, 255, 255, 0.4)', 1.5));
|
|
92
|
+
// Lines to harmony nodes
|
|
93
|
+
dyes.forEach((dye) => {
|
|
94
|
+
const dyeHue = getHueFromHex(dye.hex);
|
|
95
|
+
const dyeAngle = dyeHue - 90;
|
|
96
|
+
const dyeRad = (dyeAngle * Math.PI) / 180;
|
|
97
|
+
const dyeX = centerX + Math.cos(dyeRad) * wheelRadius * nodeRadiusRatio;
|
|
98
|
+
const dyeY = centerY + Math.sin(dyeRad) * wheelRadius * nodeRadiusRatio;
|
|
99
|
+
elements.push(createDashedLine(centerX, centerY, dyeX, dyeY, 'rgba(255, 255, 255, 0.4)', 1.5));
|
|
100
|
+
});
|
|
101
|
+
// Center swatch with glow effect (v4 style: prominent center display)
|
|
102
|
+
// Glow layer
|
|
103
|
+
elements.push(`<circle cx="${centerX}" cy="${centerY}" r="${centerSwatchRadius}" fill="${baseColor}" filter="url(#centerGlow)"/>`);
|
|
104
|
+
// Main center circle with border
|
|
105
|
+
elements.push(`<circle cx="${centerX}" cy="${centerY}" r="${centerSwatchRadius}" fill="${baseColor}" stroke="${THEME.background}" stroke-width="4"/>`);
|
|
106
|
+
// Draw harmony dye nodes (small colored dots)
|
|
107
|
+
dyes.forEach((dye) => {
|
|
108
|
+
const dyeHue = getHueFromHex(dye.hex);
|
|
109
|
+
const dyeAngle = dyeHue - 90;
|
|
110
|
+
const dyeRad = (dyeAngle * Math.PI) / 180;
|
|
111
|
+
const dyeX = centerX + Math.cos(dyeRad) * wheelRadius * nodeRadiusRatio;
|
|
112
|
+
const dyeY = centerY + Math.sin(dyeRad) * wheelRadius * nodeRadiusRatio;
|
|
113
|
+
// Small colored node with white border
|
|
114
|
+
elements.push(`<circle cx="${dyeX}" cy="${dyeY}" r="${harmonyNodeRadius}" fill="${dye.hex}" stroke="#ffffff" stroke-width="2" filter="url(#nodeShadow)"/>`);
|
|
115
|
+
});
|
|
116
|
+
// Draw base color node (slightly larger)
|
|
117
|
+
elements.push(`<circle cx="${baseX}" cy="${baseY}" r="${baseNodeRadius}" fill="${baseColor}" stroke="#ffffff" stroke-width="3" filter="url(#nodeShadow)"/>`);
|
|
118
|
+
return createSvgDocument(width, height, elements.join('\n'));
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Creates a dashed line SVG element
|
|
122
|
+
*/
|
|
123
|
+
function createDashedLine(x1, y1, x2, y2, color, strokeWidth) {
|
|
124
|
+
return `<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="${color}" stroke-width="${strokeWidth}" stroke-dasharray="6,4"/>`;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Generates a smooth color wheel ring (v4 style with reduced opacity)
|
|
128
|
+
*/
|
|
129
|
+
function generateColorWheelRing(cx, cy, radius, innerRadiusRatio = 0.6) {
|
|
130
|
+
const segments = [];
|
|
131
|
+
const segmentCount = 90; // More segments for smoother gradient
|
|
132
|
+
const segmentAngle = 360 / segmentCount;
|
|
133
|
+
const innerRadius = radius * innerRadiusRatio;
|
|
134
|
+
for (let i = 0; i < segmentCount; i++) {
|
|
135
|
+
const startAngle = i * segmentAngle;
|
|
136
|
+
const endAngle = startAngle + segmentAngle + 0.5; // Slight overlap to prevent gaps
|
|
137
|
+
const hue = startAngle;
|
|
138
|
+
// Calculate arc points
|
|
139
|
+
const startRad = ((startAngle - 90) * Math.PI) / 180;
|
|
140
|
+
const endRad = ((endAngle - 90) * Math.PI) / 180;
|
|
141
|
+
// Outer arc points
|
|
142
|
+
const ox1 = cx + radius * Math.cos(startRad);
|
|
143
|
+
const oy1 = cy + radius * Math.sin(startRad);
|
|
144
|
+
const ox2 = cx + radius * Math.cos(endRad);
|
|
145
|
+
const oy2 = cy + radius * Math.sin(endRad);
|
|
146
|
+
// Inner arc points
|
|
147
|
+
const ix1 = cx + innerRadius * Math.cos(startRad);
|
|
148
|
+
const iy1 = cy + innerRadius * Math.sin(startRad);
|
|
149
|
+
const ix2 = cx + innerRadius * Math.cos(endRad);
|
|
150
|
+
const iy2 = cy + innerRadius * Math.sin(endRad);
|
|
151
|
+
// Create wedge path
|
|
152
|
+
const path = `M ${ix1} ${iy1} L ${ox1} ${oy1} A ${radius} ${radius} 0 0 1 ${ox2} ${oy2} L ${ix2} ${iy2} A ${innerRadius} ${innerRadius} 0 0 0 ${ix1} ${iy1} Z`;
|
|
153
|
+
// v4 style: slightly reduced saturation (85%) and opacity (0.8) for softer look
|
|
154
|
+
segments.push(`<path d="${path}" fill="hsl(${hue}, 85%, 50%)" opacity="0.8" stroke="none"/>`);
|
|
155
|
+
}
|
|
156
|
+
return segments.join('\n');
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=harmony-wheel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harmony-wheel.js","sourceRoot":"","sources":["../src/harmony-wheel.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @xivdyetools/svg
|
|
3
|
+
*
|
|
4
|
+
* SVG card generators for XIV Dye Tools.
|
|
5
|
+
* All functions are pure: data in → SVG string out.
|
|
6
|
+
* Rendering to PNG (via resvg-wasm, etc.) is handled by each consuming app.
|
|
7
|
+
*
|
|
8
|
+
* @module svg
|
|
9
|
+
*/
|
|
10
|
+
export { escapeXml, hexToRgb, rgbToHex, getLuminance, getContrastTextColor, createSvgDocument, rect, circle, line, text, arcPath, group, THEME, FONTS, } from './base.js';
|
|
11
|
+
export { generateHarmonyWheel } from './harmony-wheel.js';
|
|
12
|
+
export type { HarmonyDye, HarmonyWheelOptions } from './harmony-wheel.js';
|
|
13
|
+
export { generateGradientBar, interpolateColor, generateGradientColors, } from './gradient.js';
|
|
14
|
+
export type { GradientStep, GradientBarOptions } from './gradient.js';
|
|
15
|
+
export { generatePaletteGrid, getMatchQuality, MATCH_QUALITIES, } from './palette-grid.js';
|
|
16
|
+
export type { PaletteEntry, PaletteGridOptions, PaletteGridLabels, MatchQuality, } from './palette-grid.js';
|
|
17
|
+
export { generateAccessibilityComparison, generateCompactAccessibilityRow, } from './accessibility-comparison.js';
|
|
18
|
+
export type { AccessibilityComparisonOptions, VisionType, AllVisionTypes, } from './accessibility-comparison.js';
|
|
19
|
+
export { generateContrastMatrix, calculateContrast } from './contrast-matrix.js';
|
|
20
|
+
export type { ContrastDye, ContrastMatrixOptions, ContrastResult, WCAGLevel, } from './contrast-matrix.js';
|
|
21
|
+
export { generateRandomDyesGrid } from './random-dyes-grid.js';
|
|
22
|
+
export type { RandomDyeInfo, RandomDyesGridOptions } from './random-dyes-grid.js';
|
|
23
|
+
export { generateComparisonGrid } from './comparison-grid.js';
|
|
24
|
+
export type { ComparisonGridOptions } from './comparison-grid.js';
|
|
25
|
+
export { generateDyeInfoCard } from './dye-info-card.js';
|
|
26
|
+
export type { DyeInfoCardOptions } from './dye-info-card.js';
|
|
27
|
+
export { generatePresetSwatch, generateCompactPresetSwatch, CATEGORY_DISPLAY, } from './preset-swatch.js';
|
|
28
|
+
export type { PresetSwatchOptions } from './preset-swatch.js';
|
|
29
|
+
export { generateBudgetComparison, generateNoWorldSetSvg, generateErrorSvg, formatGil, } from './budget-comparison.js';
|
|
30
|
+
export type { DyePriceData, BudgetSuggestion, BudgetSortOption, BudgetSvgLabels, BudgetComparisonOptions, } from './budget-comparison.js';
|
|
31
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EACL,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,oBAAoB,EACpB,iBAAiB,EACjB,IAAI,EACJ,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,KAAK,EACL,KAAK,EACL,KAAK,GACN,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,YAAY,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAG1E,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAGtE,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,GACb,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,+BAA+B,EAC/B,+BAA+B,GAChC,MAAM,+BAA+B,CAAC;AACvC,YAAY,EACV,8BAA8B,EAC9B,UAAU,EACV,cAAc,GACf,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACjF,YAAY,EACV,WAAW,EACX,qBAAqB,EACrB,cAAc,EACd,SAAS,GACV,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,YAAY,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAGlF,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,YAAY,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAGlE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAG7D,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAG9D,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,gBAAgB,EAChB,SAAS,GACV,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,uBAAuB,GACxB,MAAM,wBAAwB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @xivdyetools/svg
|
|
3
|
+
*
|
|
4
|
+
* SVG card generators for XIV Dye Tools.
|
|
5
|
+
* All functions are pure: data in → SVG string out.
|
|
6
|
+
* Rendering to PNG (via resvg-wasm, etc.) is handled by each consuming app.
|
|
7
|
+
*
|
|
8
|
+
* @module svg
|
|
9
|
+
*/
|
|
10
|
+
// Base utilities & primitives
|
|
11
|
+
export { escapeXml, hexToRgb, rgbToHex, getLuminance, getContrastTextColor, createSvgDocument, rect, circle, line, text, arcPath, group, THEME, FONTS, } from './base.js';
|
|
12
|
+
// Harmony Wheel
|
|
13
|
+
export { generateHarmonyWheel } from './harmony-wheel.js';
|
|
14
|
+
// Gradient Bar
|
|
15
|
+
export { generateGradientBar, interpolateColor, generateGradientColors, } from './gradient.js';
|
|
16
|
+
// Palette Grid (color extraction match results)
|
|
17
|
+
export { generatePaletteGrid, getMatchQuality, MATCH_QUALITIES, } from './palette-grid.js';
|
|
18
|
+
// Accessibility / Colorblind Comparison
|
|
19
|
+
export { generateAccessibilityComparison, generateCompactAccessibilityRow, } from './accessibility-comparison.js';
|
|
20
|
+
// WCAG Contrast Matrix
|
|
21
|
+
export { generateContrastMatrix, calculateContrast } from './contrast-matrix.js';
|
|
22
|
+
// Random Dyes Grid
|
|
23
|
+
export { generateRandomDyesGrid } from './random-dyes-grid.js';
|
|
24
|
+
// Dye Comparison Grid
|
|
25
|
+
export { generateComparisonGrid } from './comparison-grid.js';
|
|
26
|
+
// Dye Info Card
|
|
27
|
+
export { generateDyeInfoCard } from './dye-info-card.js';
|
|
28
|
+
// Preset Swatch
|
|
29
|
+
export { generatePresetSwatch, generateCompactPresetSwatch, CATEGORY_DISPLAY, } from './preset-swatch.js';
|
|
30
|
+
// Budget Comparison
|
|
31
|
+
export { generateBudgetComparison, generateNoWorldSetSvg, generateErrorSvg, formatGil, } from './budget-comparison.js';
|
|
32
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,8BAA8B;AAC9B,OAAO,EACL,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,oBAAoB,EACpB,iBAAiB,EACjB,IAAI,EACJ,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,KAAK,EACL,KAAK,EACL,KAAK,GACN,MAAM,WAAW,CAAC;AAEnB,gBAAgB;AAChB,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAG1D,eAAe;AACf,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,eAAe,CAAC;AAGvB,gDAAgD;AAChD,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAQ3B,wCAAwC;AACxC,OAAO,EACL,+BAA+B,EAC/B,+BAA+B,GAChC,MAAM,+BAA+B,CAAC;AAOvC,uBAAuB;AACvB,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAQjF,mBAAmB;AACnB,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAG/D,sBAAsB;AACtB,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAG9D,gBAAgB;AAChB,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAGzD,gBAAgB;AAChB,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAG5B,oBAAoB;AACpB,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,gBAAgB,EAChB,SAAS,GACV,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Palette Grid SVG Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates a visual comparison of extracted colors to matched FFXIV dyes.
|
|
5
|
+
* Used by the /extractor image command to display color extraction results.
|
|
6
|
+
*
|
|
7
|
+
* Layout:
|
|
8
|
+
* +----------------------------------------------------------+
|
|
9
|
+
* | [Extracted Color] 42% --> [Matched Dye] Dalamud Red |
|
|
10
|
+
* | #B01515 #AA1111 Δ8.5 [EXCELLENT] |
|
|
11
|
+
* +----------------------------------------------------------+
|
|
12
|
+
*
|
|
13
|
+
* @module svg/palette-grid
|
|
14
|
+
*/
|
|
15
|
+
import type { RGB, Dye } from '@xivdyetools/core';
|
|
16
|
+
export interface MatchQuality {
|
|
17
|
+
/** Locale key for translation lookup (e.g., 'perfect', 'excellent') */
|
|
18
|
+
key: string;
|
|
19
|
+
/** Human-readable label */
|
|
20
|
+
label: string;
|
|
21
|
+
/** Short label for display */
|
|
22
|
+
shortLabel: string;
|
|
23
|
+
/** Distance threshold for this quality level */
|
|
24
|
+
maxDistance: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Match quality thresholds
|
|
28
|
+
*
|
|
29
|
+
* Based on Euclidean distance in RGB space:
|
|
30
|
+
* - Max possible distance: ~441 (black to white)
|
|
31
|
+
* - Noticeable difference: ~10-15
|
|
32
|
+
* - Perceptually similar: ~25-30
|
|
33
|
+
*/
|
|
34
|
+
export declare const MATCH_QUALITIES: MatchQuality[];
|
|
35
|
+
/**
|
|
36
|
+
* Get the quality rating for a color distance
|
|
37
|
+
*/
|
|
38
|
+
export declare function getMatchQuality(distance: number): MatchQuality;
|
|
39
|
+
/**
|
|
40
|
+
* A single palette entry with extracted and matched colors
|
|
41
|
+
*/
|
|
42
|
+
export interface PaletteEntry {
|
|
43
|
+
/** The extracted RGB color from the image */
|
|
44
|
+
extracted: RGB;
|
|
45
|
+
/** The closest matching FFXIV dye */
|
|
46
|
+
matchedDye: Dye;
|
|
47
|
+
/** Color distance (Euclidean in RGB space) */
|
|
48
|
+
distance: number;
|
|
49
|
+
/** Percentage of pixels with this color (0-100) */
|
|
50
|
+
dominance: number;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Translatable labels for the palette grid SVG.
|
|
54
|
+
* Pass these from the bot's i18n system to localize the image.
|
|
55
|
+
*/
|
|
56
|
+
export interface PaletteGridLabels {
|
|
57
|
+
/** Label above extracted color (e.g., "EXTRACTED") */
|
|
58
|
+
extracted: string;
|
|
59
|
+
/** Label above matched dye (e.g., "MATCHED DYE") */
|
|
60
|
+
matchedDye: string;
|
|
61
|
+
/** Suffix for dominance percentage (e.g., "of image") */
|
|
62
|
+
ofImage: string;
|
|
63
|
+
/** Empty state message (e.g., "No colors extracted from image") */
|
|
64
|
+
noColors: string;
|
|
65
|
+
/** Quality badge labels keyed by quality key */
|
|
66
|
+
quality: Record<string, string>;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Options for generating the palette grid
|
|
70
|
+
*/
|
|
71
|
+
export interface PaletteGridOptions {
|
|
72
|
+
/** Array of palette entries to display */
|
|
73
|
+
entries: PaletteEntry[];
|
|
74
|
+
/** Canvas width in pixels (default: 800) */
|
|
75
|
+
width?: number;
|
|
76
|
+
/** Show color distance values (default: true) */
|
|
77
|
+
showDistance?: boolean;
|
|
78
|
+
/** Title text (optional) */
|
|
79
|
+
title?: string;
|
|
80
|
+
/** Translated labels for i18n (defaults to English if omitted) */
|
|
81
|
+
labels?: PaletteGridLabels;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Generate a palette grid SVG showing extracted colors matched to dyes
|
|
85
|
+
*
|
|
86
|
+
* @param options - Palette grid configuration
|
|
87
|
+
* @returns SVG string
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* const svg = generatePaletteGrid({
|
|
92
|
+
* entries: [
|
|
93
|
+
* {
|
|
94
|
+
* extracted: { r: 176, g: 21, b: 21 },
|
|
95
|
+
* matchedDye: { name: 'Dalamud Red', hex: '#AA1111', ... },
|
|
96
|
+
* distance: 8.5,
|
|
97
|
+
* dominance: 42,
|
|
98
|
+
* },
|
|
99
|
+
* ],
|
|
100
|
+
* });
|
|
101
|
+
* const png = await renderSvgToPng(svg);
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export declare function generatePaletteGrid(options: PaletteGridOptions): string;
|
|
105
|
+
//# sourceMappingURL=palette-grid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"palette-grid.d.ts","sourceRoot":"","sources":["../src/palette-grid.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAgBlD,MAAM,WAAW,YAAY;IAC3B,uEAAuE;IACvE,GAAG,EAAE,MAAM,CAAC;IACZ,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,EAAE,YAAY,EAMzC,CAAC;AAEF;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,CAO9D;AAMD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,6CAA6C;IAC7C,SAAS,EAAE,GAAG,CAAC;IACf,qCAAqC;IACrC,UAAU,EAAE,GAAG,CAAC;IAChB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,QAAQ,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,0CAA0C;IAC1C,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,4BAA4B;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAkCD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CA2DvE"}
|