@xivdyetools/core 2.6.0 → 4.0.1
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 +85 -67
- package/dist/blending/blending.d.ts +22 -0
- package/dist/blending/blending.d.ts.map +1 -0
- package/dist/blending/blending.js +129 -0
- package/dist/blending/blending.js.map +1 -0
- package/dist/blending/conversions.d.ts +53 -0
- package/dist/blending/conversions.d.ts.map +1 -0
- package/dist/blending/conversions.js +256 -0
- package/dist/blending/conversions.js.map +1 -0
- package/dist/blending/index.d.ts +8 -0
- package/dist/blending/index.d.ts.map +1 -0
- package/dist/blending/index.js +3 -0
- package/dist/blending/index.js.map +1 -0
- package/dist/blending/types.d.ts +36 -0
- package/dist/blending/types.d.ts.map +1 -0
- package/dist/blending/types.js +21 -0
- package/dist/blending/types.js.map +1 -0
- package/dist/config/band-calibration.d.ts +68 -0
- package/dist/config/band-calibration.d.ts.map +1 -0
- package/dist/config/band-calibration.js +196 -0
- package/dist/config/band-calibration.js.map +1 -0
- package/dist/config/band-vocabulary.d.ts +82 -0
- package/dist/config/band-vocabulary.d.ts.map +1 -0
- package/dist/config/band-vocabulary.js +117 -0
- package/dist/config/band-vocabulary.js.map +1 -0
- package/dist/config/consolidated-ids.js +2 -2
- package/dist/config/consolidated-ids.js.map +1 -1
- package/dist/config/dye-vocabulary.d.ts +45 -0
- package/dist/config/dye-vocabulary.d.ts.map +1 -0
- package/dist/config/dye-vocabulary.js +58 -0
- package/dist/config/dye-vocabulary.js.map +1 -0
- package/dist/config/facewear.d.ts +24 -0
- package/dist/config/facewear.d.ts.map +1 -0
- package/dist/config/facewear.js +35 -0
- package/dist/config/facewear.js.map +1 -0
- package/dist/config/learn-links.d.ts +70 -0
- package/dist/config/learn-links.d.ts.map +1 -0
- package/dist/config/learn-links.js +171 -0
- package/dist/config/learn-links.js.map +1 -0
- package/dist/config/product-links.d.ts +44 -0
- package/dist/config/product-links.d.ts.map +1 -0
- package/dist/config/product-links.js +44 -0
- package/dist/config/product-links.js.map +1 -0
- package/dist/constants/index.d.ts +14 -1
- package/dist/constants/index.d.ts.map +1 -1
- package/dist/constants/index.js +38 -22
- package/dist/constants/index.js.map +1 -1
- package/dist/data/character_colors/race_specific/hair_colors.json +1 -1
- package/dist/data/character_colors/race_specific/skin_colors.json +1 -1
- package/dist/data/dyes.json +1127 -0
- package/dist/data/facewear_colors.json +57 -0
- package/dist/data/locales/de.json +4 -50
- package/dist/data/locales/en.json +4 -50
- package/dist/data/locales/fr.json +4 -50
- package/dist/data/locales/ja.json +4 -50
- package/dist/data/locales/ko.json +4 -50
- package/dist/data/locales/zh.json +4 -50
- package/dist/data/presets.json +59 -301
- package/dist/index.d.ts +156 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +114 -10
- package/dist/index.js.map +1 -1
- package/dist/services/APIService.d.ts +39 -62
- package/dist/services/APIService.d.ts.map +1 -1
- package/dist/services/APIService.js +156 -150
- package/dist/services/APIService.js.map +1 -1
- package/dist/services/CharacterColorService.d.ts +4 -36
- package/dist/services/CharacterColorService.d.ts.map +1 -1
- package/dist/services/CharacterColorService.js +57 -79
- package/dist/services/CharacterColorService.js.map +1 -1
- package/dist/services/ColorService.d.ts +57 -68
- package/dist/services/ColorService.d.ts.map +1 -1
- package/dist/services/ColorService.js +86 -94
- package/dist/services/ColorService.js.map +1 -1
- package/dist/services/DyeService.d.ts +11 -104
- package/dist/services/DyeService.d.ts.map +1 -1
- package/dist/services/DyeService.js +19 -157
- package/dist/services/DyeService.js.map +1 -1
- package/dist/services/LocalizationService.d.ts +48 -59
- package/dist/services/LocalizationService.d.ts.map +1 -1
- package/dist/services/LocalizationService.js +86 -95
- package/dist/services/LocalizationService.js.map +1 -1
- package/dist/services/PaletteService.d.ts +8 -9
- package/dist/services/PaletteService.d.ts.map +1 -1
- package/dist/services/PaletteService.js +10 -22
- package/dist/services/PaletteService.js.map +1 -1
- package/dist/services/PresetService.d.ts +2 -34
- package/dist/services/PresetService.d.ts.map +1 -1
- package/dist/services/PresetService.js +12 -59
- package/dist/services/PresetService.js.map +1 -1
- package/dist/services/chara/chara-models.d.ts +68 -0
- package/dist/services/chara/chara-models.d.ts.map +1 -0
- package/dist/services/chara/chara-models.js +87 -0
- package/dist/services/chara/chara-models.js.map +1 -0
- package/dist/services/chara/chara-parser.d.ts +95 -0
- package/dist/services/chara/chara-parser.d.ts.map +1 -0
- package/dist/services/chara/chara-parser.js +299 -0
- package/dist/services/chara/chara-parser.js.map +1 -0
- package/dist/services/chara/chara-resolver.d.ts +103 -0
- package/dist/services/chara/chara-resolver.d.ts.map +1 -0
- package/dist/services/chara/chara-resolver.js +233 -0
- package/dist/services/chara/chara-resolver.js.map +1 -0
- package/dist/services/color/ColorConverter.d.ts +112 -35
- package/dist/services/color/ColorConverter.d.ts.map +1 -1
- package/dist/services/color/ColorConverter.js +205 -89
- package/dist/services/color/ColorConverter.js.map +1 -1
- package/dist/services/color/ColorManipulator.d.ts +11 -0
- package/dist/services/color/ColorManipulator.d.ts.map +1 -1
- package/dist/services/color/ColorManipulator.js +24 -9
- package/dist/services/color/ColorManipulator.js.map +1 -1
- package/dist/services/color/ColorblindnessSimulator.d.ts +17 -0
- package/dist/services/color/ColorblindnessSimulator.d.ts.map +1 -1
- package/dist/services/color/ColorblindnessSimulator.js +57 -3
- package/dist/services/color/ColorblindnessSimulator.js.map +1 -1
- package/dist/services/color/SpectralMixer.d.ts +0 -34
- package/dist/services/color/SpectralMixer.d.ts.map +1 -1
- package/dist/services/color/SpectralMixer.js +0 -73
- package/dist/services/color/SpectralMixer.js.map +1 -1
- package/dist/services/dye/DyeDatabase.d.ts +5 -21
- package/dist/services/dye/DyeDatabase.d.ts.map +1 -1
- package/dist/services/dye/DyeDatabase.js +98 -130
- package/dist/services/dye/DyeDatabase.js.map +1 -1
- package/dist/services/dye/DyeSearch.d.ts +17 -31
- package/dist/services/dye/DyeSearch.d.ts.map +1 -1
- package/dist/services/dye/DyeSearch.js +45 -141
- package/dist/services/dye/DyeSearch.js.map +1 -1
- package/dist/services/dye/HarmonyGenerator.d.ts +11 -18
- package/dist/services/dye/HarmonyGenerator.d.ts.map +1 -1
- package/dist/services/dye/HarmonyGenerator.js +33 -38
- package/dist/services/dye/HarmonyGenerator.js.map +1 -1
- package/dist/services/localization/LocaleLoader.d.ts.map +1 -1
- package/dist/services/localization/LocaleLoader.js +0 -1
- package/dist/services/localization/LocaleLoader.js.map +1 -1
- package/dist/services/localization/TranslationProvider.d.ts +1 -42
- package/dist/services/localization/TranslationProvider.d.ts.map +1 -1
- package/dist/services/localization/TranslationProvider.js +4 -82
- package/dist/services/localization/TranslationProvider.js.map +1 -1
- package/dist/types/index.d.ts +39 -52
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +50 -10
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +36 -123
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +54 -413
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/kd-tree.d.ts +0 -4
- package/dist/utils/kd-tree.d.ts.map +1 -1
- package/dist/utils/kd-tree.js +0 -6
- package/dist/utils/kd-tree.js.map +1 -1
- package/package.json +24 -15
- package/dist/data/character_colors/index.json +0 -40
- package/dist/data/colors_xiv.json +0 -3538
- package/dist/version.d.ts +0 -11
- package/dist/version.d.ts.map +0 -1
- package/dist/version.js +0 -11
- package/dist/version.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
# xivdyetools
|
|
1
|
+
# @xivdyetools/core
|
|
2
2
|
|
|
3
|
-
> Core color algorithms and dye database for XIV Dye Tools
|
|
3
|
+
> Core color algorithms and dye database for XIV Dye Tools — environment-agnostic TypeScript library for FFXIV dye color matching, harmony generation, and accessibility checking.
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/@xivdyetools/core)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
|
-
[](https://www.typescriptlang.org/)
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
|
-
✨ **Color Conversion** - RGB ↔ HSV ↔ Hex ↔ LAB ↔ RYB ↔ OKLAB ↔ OKLCH ↔ LCH ↔ HSL
|
|
12
|
-
🎨 **
|
|
13
|
-
🖌️ **Advanced Color Mixing** - RYB, OKLAB, HSL, and Spectral (Kubelka-Munk)
|
|
11
|
+
✨ **Color Conversion** - RGB ↔ HSV ↔ Hex ↔ LAB ↔ RYB ↔ OKLAB ↔ OKLCH ↔ LCH ↔ HSL ↔ CMYK
|
|
12
|
+
🎨 **125 FFXIV Dyes** - Complete database (schema v2, stainID-keyed) plus 11 Facewear colors
|
|
13
|
+
🖌️ **Advanced Color Mixing** - RYB, OKLAB, HSL, and Spectral (Kubelka-Munk); six blending modes via `@xivdyetools/core/blending`
|
|
14
14
|
🔬 **Spectral.js Integration** - Physics-based paint mixing (Blue + Yellow = Green!)
|
|
15
15
|
🎯 **Dye Matching** - Find closest dyes to any color
|
|
16
16
|
🌈 **Color Harmonies** - Triadic, complementary, analogous, and more
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
## Installation
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
|
-
npm install xivdyetools
|
|
27
|
+
npm install @xivdyetools/core
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
## Quick Start
|
|
@@ -32,7 +32,7 @@ npm install xivdyetools-core
|
|
|
32
32
|
### Browser (with bundler)
|
|
33
33
|
|
|
34
34
|
```typescript
|
|
35
|
-
import { ColorService, DyeService, dyeDatabase } from 'xivdyetools
|
|
35
|
+
import { ColorService, DyeService, dyeDatabase } from '@xivdyetools/core';
|
|
36
36
|
|
|
37
37
|
// Initialize services
|
|
38
38
|
const dyeService = new DyeService(dyeDatabase);
|
|
@@ -57,18 +57,22 @@ console.log(hsv); // { h: 0, s: 58.04, v: 100 }
|
|
|
57
57
|
import {
|
|
58
58
|
DyeService,
|
|
59
59
|
APIService,
|
|
60
|
-
dyeDatabase
|
|
61
|
-
|
|
60
|
+
dyeDatabase,
|
|
61
|
+
getMarketItemID
|
|
62
|
+
} from '@xivdyetools/core';
|
|
62
63
|
import Redis from 'ioredis';
|
|
64
|
+
// RedisCacheBackend is your own ICacheBackend implementation — see "Custom Cache Backends" below
|
|
63
65
|
|
|
64
66
|
// Initialize with Redis cache (for Discord bots)
|
|
65
67
|
const redis = new Redis();
|
|
66
68
|
const cacheBackend = new RedisCacheBackend(redis);
|
|
67
|
-
const apiService = new APIService(cacheBackend);
|
|
69
|
+
const apiService = new APIService({ cacheBackend });
|
|
68
70
|
const dyeService = new DyeService(dyeDatabase);
|
|
69
71
|
|
|
70
|
-
// Fetch live market prices
|
|
71
|
-
|
|
72
|
+
// Fetch live market prices.
|
|
73
|
+
// NOTE: since Patch 7.5, most dyes share a consolidated market itemID —
|
|
74
|
+
// use getMarketItemID(dye) rather than a hard-coded legacy itemID.
|
|
75
|
+
const priceData = await apiService.getPriceData(getMarketItemID(jetBlack));
|
|
72
76
|
console.log(`${priceData.currentMinPrice} Gil`);
|
|
73
77
|
|
|
74
78
|
// Find harmony with pricing
|
|
@@ -85,7 +89,7 @@ Pure color conversion and manipulation algorithms.
|
|
|
85
89
|
> **Memory Note**: ColorService uses LRU caches (5 caches × 1000 entries each = up to 5000 cached entries) for performance optimization. For long-running applications or memory-constrained environments, call `ColorService.clearCaches()` periodically to free memory. Each cache entry is approximately 50-100 bytes, so maximum memory usage is ~500KB.
|
|
86
90
|
|
|
87
91
|
```typescript
|
|
88
|
-
import { ColorService } from 'xivdyetools
|
|
92
|
+
import { ColorService } from '@xivdyetools/core';
|
|
89
93
|
|
|
90
94
|
// Hex ↔ RGB
|
|
91
95
|
const rgb = ColorService.hexToRgb('#FF6B6B');
|
|
@@ -107,7 +111,8 @@ const distance = ColorService.getColorDistance('#FF0000', '#00FF00');
|
|
|
107
111
|
// LAB color space and DeltaE (perceptual color difference)
|
|
108
112
|
const lab = ColorService.hexToLab('#FF6B6B');
|
|
109
113
|
const deltaE = ColorService.getDeltaE('#FF0000', '#FF6B6B'); // CIE76 by default
|
|
110
|
-
const deltaE2000 = ColorService.getDeltaE('#FF0000', '#FF6B6B', '
|
|
114
|
+
const deltaE2000 = ColorService.getDeltaE('#FF0000', '#FF6B6B', 'ciede2000'); // CIEDE2000
|
|
115
|
+
// 'cie2000' is accepted as a legacy alias of 'ciede2000' and returns the same value
|
|
111
116
|
|
|
112
117
|
// Color inversion
|
|
113
118
|
const inverted = ColorService.invert('#FF6B6B');
|
|
@@ -132,19 +137,21 @@ const hex = ColorService.rybToHex(255, 255, 0); // Red+Yellow = Orange
|
|
|
132
137
|
FFXIV dye database management and color matching.
|
|
133
138
|
|
|
134
139
|
```typescript
|
|
135
|
-
import { DyeService, dyeDatabase } from 'xivdyetools
|
|
140
|
+
import { DyeService, dyeDatabase } from '@xivdyetools/core';
|
|
136
141
|
|
|
137
142
|
const dyeService = new DyeService(dyeDatabase);
|
|
138
143
|
|
|
139
144
|
// Database access
|
|
140
|
-
const allDyes = dyeService.getAllDyes(); //
|
|
141
|
-
const dyeById = dyeService.getDyeById(
|
|
142
|
-
const dyeByStain = dyeService.getByStainId(1); // By stainID - Snow White
|
|
145
|
+
const allDyes = dyeService.getAllDyes(); // 125 dyes
|
|
146
|
+
const dyeById = dyeService.getDyeById(13115); // By itemID (= Dye.id) - Jet Black; prefer getByStainId(102)
|
|
147
|
+
const dyeByStain = dyeService.getByStainId(1); // By stainID (canonical key) - Snow White
|
|
143
148
|
const categories = dyeService.getCategories(); // ['Neutral', 'Red', 'Blue', ...]
|
|
144
149
|
|
|
145
|
-
// Color matching
|
|
150
|
+
// Color matching — matchingMethod is one of the 5.0 suite:
|
|
151
|
+
// 'ciede2000' (default) | 'oklab' | 'cie76' | 'redmean' | 'rgb' | 'distinguish'
|
|
146
152
|
const closest = dyeService.findClosestDye('#FF6B6B');
|
|
147
|
-
const
|
|
153
|
+
const closestOk = dyeService.findClosestDye('#FF6B6B', { matchingMethod: 'oklab' });
|
|
154
|
+
const nearby = dyeService.findDyesWithinDistance('#FF6B6B', { maxDistance: 50, limit: 5 });
|
|
148
155
|
|
|
149
156
|
// Harmony generation (default: fast hue-based matching)
|
|
150
157
|
const triadic = dyeService.findTriadicDyes('#FF6B6B');
|
|
@@ -156,10 +163,10 @@ const splitComplementary = dyeService.findSplitComplementaryDyes('#FF6B6B');
|
|
|
156
163
|
// DeltaE-based harmony (perceptually accurate matching)
|
|
157
164
|
const triadicDeltaE = dyeService.findTriadicDyes('#FF6B6B', {
|
|
158
165
|
algorithm: 'deltaE',
|
|
159
|
-
deltaEFormula: '
|
|
166
|
+
deltaEFormula: 'ciede2000', // or 'cie76' (faster, default); 'cie2000' is a legacy alias
|
|
160
167
|
});
|
|
161
168
|
|
|
162
|
-
// Color space selection for hue rotation
|
|
169
|
+
// Color space selection for hue rotation
|
|
163
170
|
// OKLCH produces more perceptually balanced harmonies
|
|
164
171
|
const triadicOklch = dyeService.findTriadicDyes('#FF6B6B', { colorSpace: 'oklch' });
|
|
165
172
|
const compLch = dyeService.findComplementaryPair('#FF6B6B', { colorSpace: 'lch' });
|
|
@@ -181,7 +188,7 @@ const filtered = dyeService.filterDyes({
|
|
|
181
188
|
Multi-color palette extraction from images using K-means++ clustering.
|
|
182
189
|
|
|
183
190
|
```typescript
|
|
184
|
-
import { PaletteService, DyeService, dyeDatabase } from 'xivdyetools
|
|
191
|
+
import { PaletteService, DyeService, dyeDatabase } from '@xivdyetools/core';
|
|
185
192
|
|
|
186
193
|
const paletteService = new PaletteService();
|
|
187
194
|
const dyeService = new DyeService(dyeDatabase);
|
|
@@ -203,9 +210,6 @@ const matches = paletteService.extractAndMatchPalette(pixels, dyeService, {
|
|
|
203
210
|
});
|
|
204
211
|
// Returns: Array<{ extracted: RGB, matchedDye: Dye, distance: number, dominance: number }>
|
|
205
212
|
|
|
206
|
-
// Helper: Convert raw pixel buffer (RGB, 3 bytes per pixel)
|
|
207
|
-
const pixelsFromBuffer = PaletteService.pixelDataToRGB(buffer);
|
|
208
|
-
|
|
209
213
|
// Helper: Convert RGBA ImageData, filtering transparent pixels
|
|
210
214
|
const pixelsFromCanvas = PaletteService.pixelDataToRGBFiltered(imageData.data);
|
|
211
215
|
```
|
|
@@ -215,32 +219,30 @@ const pixelsFromCanvas = PaletteService.pixelDataToRGBFiltered(imageData.data);
|
|
|
215
219
|
Universalis API integration with pluggable cache backends.
|
|
216
220
|
|
|
217
221
|
```typescript
|
|
218
|
-
import { APIService, MemoryCacheBackend } from 'xivdyetools
|
|
222
|
+
import { APIService, MemoryCacheBackend } from '@xivdyetools/core';
|
|
219
223
|
|
|
220
224
|
// With memory cache (default)
|
|
221
225
|
const apiService = new APIService();
|
|
222
226
|
|
|
223
227
|
// With custom cache backend
|
|
224
228
|
const cache = new MemoryCacheBackend();
|
|
225
|
-
const apiService = new APIService(cache);
|
|
229
|
+
const apiService = new APIService({ cacheBackend: cache });
|
|
226
230
|
|
|
227
231
|
// Fetch price data
|
|
228
232
|
const priceData = await apiService.getPriceData(5752); // itemID
|
|
229
233
|
const pricesWithDC = await apiService.getPriceData(5752, undefined, 'Aether');
|
|
230
234
|
|
|
231
|
-
// Batch operations
|
|
232
|
-
const prices = await apiService.
|
|
235
|
+
// Batch operations (per data center)
|
|
236
|
+
const prices = await apiService.getPricesForDataCenter([5752, 5753, 5754], 'Aether');
|
|
233
237
|
|
|
234
238
|
// Cache management
|
|
235
239
|
await apiService.clearCache();
|
|
236
|
-
const stats = await apiService.getCacheStats();
|
|
237
240
|
|
|
238
241
|
// API health check
|
|
239
242
|
const { available, latency } = await apiService.getAPIStatus();
|
|
240
243
|
|
|
241
244
|
// Utility methods
|
|
242
245
|
const formatted = APIService.formatPrice(123456); // "123,456G"
|
|
243
|
-
const trend = APIService.getPriceTrend(100, 80); // { trend: 'up', ... }
|
|
244
246
|
```
|
|
245
247
|
|
|
246
248
|
## Custom Cache Backends
|
|
@@ -248,7 +250,7 @@ const trend = APIService.getPriceTrend(100, 80); // { trend: 'up', ... }
|
|
|
248
250
|
Implement the `ICacheBackend` interface for custom storage:
|
|
249
251
|
|
|
250
252
|
```typescript
|
|
251
|
-
import { ICacheBackend, CachedData, PriceData } from 'xivdyetools
|
|
253
|
+
import { ICacheBackend, CachedData, PriceData } from '@xivdyetools/core';
|
|
252
254
|
import Redis from 'ioredis';
|
|
253
255
|
|
|
254
256
|
class RedisCacheBackend implements ICacheBackend {
|
|
@@ -279,7 +281,7 @@ class RedisCacheBackend implements ICacheBackend {
|
|
|
279
281
|
// Use with APIService
|
|
280
282
|
const redis = new Redis();
|
|
281
283
|
const cache = new RedisCacheBackend(redis);
|
|
282
|
-
const apiService = new APIService(cache);
|
|
284
|
+
const apiService = new APIService({ cacheBackend: cache });
|
|
283
285
|
```
|
|
284
286
|
|
|
285
287
|
## TypeScript Types
|
|
@@ -303,7 +305,7 @@ import type {
|
|
|
303
305
|
HarmonyMatchingAlgorithm,
|
|
304
306
|
HarmonyColorSpace,
|
|
305
307
|
DeltaEFormula
|
|
306
|
-
} from 'xivdyetools
|
|
308
|
+
} from '@xivdyetools/core';
|
|
307
309
|
```
|
|
308
310
|
|
|
309
311
|
## Constants
|
|
@@ -314,11 +316,10 @@ Access color theory and API configuration constants:
|
|
|
314
316
|
import {
|
|
315
317
|
RGB_MAX,
|
|
316
318
|
HUE_MAX,
|
|
317
|
-
VISION_TYPES,
|
|
318
319
|
BRETTEL_MATRICES,
|
|
319
320
|
UNIVERSALIS_API_BASE,
|
|
320
321
|
API_CACHE_TTL
|
|
321
|
-
} from 'xivdyetools
|
|
322
|
+
} from '@xivdyetools/core';
|
|
322
323
|
```
|
|
323
324
|
|
|
324
325
|
## Utilities
|
|
@@ -328,20 +329,18 @@ Helper functions for common tasks:
|
|
|
328
329
|
```typescript
|
|
329
330
|
import {
|
|
330
331
|
clamp,
|
|
331
|
-
lerp,
|
|
332
332
|
isValidHexColor,
|
|
333
333
|
isValidRGB,
|
|
334
334
|
retry,
|
|
335
335
|
sleep,
|
|
336
336
|
generateChecksum
|
|
337
|
-
} from 'xivdyetools
|
|
337
|
+
} from '@xivdyetools/core';
|
|
338
338
|
|
|
339
339
|
// Validation
|
|
340
340
|
const isValid = isValidHexColor('#FF6B6B'); // true
|
|
341
341
|
|
|
342
342
|
// Math
|
|
343
343
|
const clamped = clamp(150, 0, 100); // 100
|
|
344
|
-
const interpolated = lerp(0, 100, 0.5); // 50
|
|
345
344
|
|
|
346
345
|
// Async utilities
|
|
347
346
|
await sleep(1000); // Wait 1 second
|
|
@@ -353,7 +352,7 @@ const result = await retry(() => fetchData(), 3, 1000); // Retry with backoff
|
|
|
353
352
|
### Discord Bot
|
|
354
353
|
```typescript
|
|
355
354
|
// Implement /harmony command
|
|
356
|
-
import { DyeService, dyeDatabase } from 'xivdyetools
|
|
355
|
+
import { DyeService, dyeDatabase } from '@xivdyetools/core';
|
|
357
356
|
|
|
358
357
|
const dyeService = new DyeService(dyeDatabase);
|
|
359
358
|
const baseDye = dyeService.findClosestDye(userColor);
|
|
@@ -364,27 +363,35 @@ const harmonyDyes = dyeService.findTriadicDyes(userColor);
|
|
|
364
363
|
### Web App
|
|
365
364
|
```typescript
|
|
366
365
|
// Color matcher tool
|
|
367
|
-
import { DyeService, dyeDatabase } from 'xivdyetools
|
|
366
|
+
import { DyeService, dyeDatabase } from '@xivdyetools/core';
|
|
368
367
|
|
|
369
368
|
const dyeService = new DyeService(dyeDatabase);
|
|
370
|
-
const matchingDyes = dyeService.findDyesWithinDistance(imageColor, 50, 10);
|
|
369
|
+
const matchingDyes = dyeService.findDyesWithinDistance(imageColor, { maxDistance: 50, limit: 10 });
|
|
371
370
|
// Display results in UI
|
|
372
371
|
```
|
|
373
372
|
|
|
374
373
|
### CLI Tool
|
|
375
374
|
```typescript
|
|
376
375
|
// Color conversion utility
|
|
377
|
-
import { ColorService } from 'xivdyetools
|
|
376
|
+
import { ColorService } from '@xivdyetools/core';
|
|
378
377
|
|
|
379
378
|
const hex = process.argv[2];
|
|
380
379
|
const rgb = ColorService.hexToRgb(hex);
|
|
381
380
|
console.log(`RGB: ${rgb.r}, ${rgb.g}, ${rgb.b}`);
|
|
382
381
|
```
|
|
383
382
|
|
|
383
|
+
## Dye Database Composition
|
|
384
|
+
|
|
385
|
+
The database is **125 standard dyes** (`src/data/dyes.json`, schema v2) keyed by `stainID`. Seven fields are stored per entry — `stainID`, `name`, `hex`, `category`, `acquisition`, `consolidationType`, `legacyItemID` — and everything else (`rgb` / `hsv` / `lab`, `cost` / `currency`, the `is*` flags) is **derived** at `DyeDatabase.initialize()`. The runtime `Dye` object still has its full shape, and `Dye.itemID` is always a `number`.
|
|
386
|
+
|
|
387
|
+
The **11 Facewear colors are not dyes.** They live separately in `facewear_colors.json` / the `facewearColors` export as `FacewearColor` objects (string slug `id`, `name`, `hex`) and are excluded from the k-d tree, since they are not market-tradeable.
|
|
388
|
+
|
|
389
|
+
Since **Patch 7.5**, 105 of the 125 dyes share three consolidated market itemIDs (Type-A `52254`, Type-B `52255`, Type-C `52256`). Use `getMarketItemID(dye)` for any market-board lookup — a hard-coded legacy itemID will not price correctly.
|
|
390
|
+
|
|
384
391
|
## Requirements
|
|
385
392
|
|
|
386
|
-
- **Node.js**
|
|
387
|
-
- **TypeScript** 5.
|
|
393
|
+
- **Node.js** 22.0.0 or higher
|
|
394
|
+
- **TypeScript** 5.9 or higher (for development)
|
|
388
395
|
|
|
389
396
|
## Browser Compatibility
|
|
390
397
|
|
|
@@ -393,44 +400,55 @@ Works in all modern browsers with ES6 module support:
|
|
|
393
400
|
- Firefox 88+
|
|
394
401
|
- Safari 15+
|
|
395
402
|
|
|
396
|
-
##
|
|
397
|
-
|
|
398
|
-
MIT © 2025-2026 Flash Galatine
|
|
399
|
-
|
|
400
|
-
See [LICENSE](./LICENSE) for full details.
|
|
401
|
-
|
|
402
|
-
## Legal Notice
|
|
403
|
-
|
|
404
|
-
**This is a fan-made tool and is not affiliated with or endorsed by Square Enix Co., Ltd. FINAL FANTASY is a registered trademark of Square Enix Holdings Co., Ltd.**
|
|
403
|
+
## Related Projects
|
|
405
404
|
|
|
406
|
-
|
|
405
|
+
This package lives in the [xivdyetools monorepo](https://github.com/FlashGalatine/xivdyetools). Its direct consumers:
|
|
407
406
|
|
|
408
|
-
|
|
407
|
+
- [`apps/web-app`](../../apps/web-app/) — interactive color tools for FFXIV
|
|
408
|
+
- [`apps/discord-worker`](../../apps/discord-worker/) — Cloudflare Worker Discord bot
|
|
409
|
+
- [`apps/api-worker`](../../apps/api-worker/) — public REST API
|
|
410
|
+
- [`apps/og-worker`](../../apps/og-worker/) — OpenGraph cards (stateless localization trio)
|
|
411
|
+
- [`apps/stoat-worker`](../../apps/stoat-worker/) — Revolt bot (parked)
|
|
412
|
+
- [`@xivdyetools/svg`](../svg/), [`@xivdyetools/bot-logic`](../bot-logic/)
|
|
409
413
|
|
|
410
|
-
##
|
|
414
|
+
## Support
|
|
411
415
|
|
|
412
|
-
- [
|
|
413
|
-
-
|
|
416
|
+
- **Issues**: [GitHub Issues](https://github.com/FlashGalatine/xivdyetools/issues)
|
|
417
|
+
- **NPM Package**: [@xivdyetools/core](https://www.npmjs.com/package/@xivdyetools/core)
|
|
418
|
+
- **API Docs**: [developers.xivdyetools.app](https://developers.xivdyetools.app)
|
|
414
419
|
|
|
415
|
-
##
|
|
420
|
+
## Credits & Acknowledgements
|
|
416
421
|
|
|
417
|
-
- **
|
|
418
|
-
- **
|
|
419
|
-
- **
|
|
422
|
+
- **[XIVAPI](https://xivapi.com/)** — dye names in English, Japanese, German, and French. Korean and Chinese names are manually sourced; XIVAPI does not serve them.
|
|
423
|
+
- **[Universalis](https://universalis.app/)** (MIT) — market board price data consumed by `APIService`.
|
|
424
|
+
- **[spectral.js](https://github.com/rvanwijnen/spectral.js)** (MIT) — Kubelka-Munk spectral paint mixing.
|
|
425
|
+
- Color-vision deficiency simulation uses the matrices from **Brettel, Viénot & Mollon (1997)**, *"Computerized simulation of color appearance for dichromats"*, JOSA A 14(10).
|
|
426
|
+
- Perceptual color difference uses **CIE76** and **CIEDE2000** as published by the International Commission on Illumination.
|
|
420
427
|
|
|
421
428
|
## Connect With Me
|
|
422
429
|
|
|
423
430
|
**Flash Galatine** | Midgardsormr (Aether)
|
|
424
431
|
|
|
425
432
|
🎮 **FFXIV**: [Lodestone Character](https://na.finalfantasyxiv.com/lodestone/character/7677106/)
|
|
426
|
-
📝 **Blog**: [Project Galatine](https://blog.projectgalatine.com/)
|
|
427
433
|
💻 **GitHub**: [@FlashGalatine](https://github.com/FlashGalatine)
|
|
434
|
+
🐦 **X/Twitter**: [@AsheJunius](https://x.com/AsheJunius)
|
|
428
435
|
📺 **Twitch**: [flashgalatine](https://www.twitch.tv/flashgalatine)
|
|
429
436
|
🌐 **BlueSky**: [projectgalatine.com](https://bsky.app/profile/projectgalatine.com)
|
|
430
437
|
❤️ **Patreon**: [ProjectGalatine](https://patreon.com/ProjectGalatine)
|
|
431
438
|
☕ **Ko-Fi**: [flashgalatine](https://ko-fi.com/flashgalatine)
|
|
432
439
|
💬 **Discord**: [Join Server](https://discord.gg/5VUSKTZCe5)
|
|
433
440
|
|
|
441
|
+
## License
|
|
442
|
+
|
|
443
|
+
MIT © 2025-2026 Flash Galatine — see [LICENSE](./LICENSE).
|
|
444
|
+
|
|
445
|
+
## Legal Notice
|
|
446
|
+
|
|
447
|
+
**FINAL FANTASY is a registered trademark of Square Enix Holdings Co., Ltd.**
|
|
448
|
+
**FINAL FANTASY XIV © SQUARE ENIX CO., LTD.**
|
|
449
|
+
|
|
450
|
+
XIV Dye Tools is an unofficial fan project and is **not affiliated with, endorsed by, or sponsored by Square Enix Co., Ltd.** All FINAL FANTASY XIV content, including dye names and color values, is the property of Square Enix.
|
|
451
|
+
|
|
434
452
|
---
|
|
435
453
|
|
|
436
454
|
**Made with ❤️ for the FFXIV community**
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Color Blending — Six algorithms for mixing two colors.
|
|
3
|
+
*
|
|
4
|
+
* Blending Modes:
|
|
5
|
+
* - RGB: Simple additive channel averaging
|
|
6
|
+
* - LAB: Perceptually uniform CIELAB blending
|
|
7
|
+
* - OKLAB: Modern perceptual (fixes LAB blue→purple issue)
|
|
8
|
+
* - RYB: Traditional artist's color wheel
|
|
9
|
+
* - HSL: Hue-Saturation-Lightness interpolation
|
|
10
|
+
* - Spectral: Kubelka-Munk physics simulation
|
|
11
|
+
*/
|
|
12
|
+
import type { BlendResult, BlendingMode } from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Blend two colors using the specified blending mode.
|
|
15
|
+
*
|
|
16
|
+
* @param hex1 - First color hex code (with or without #)
|
|
17
|
+
* @param hex2 - Second color hex code (with or without #)
|
|
18
|
+
* @param mode - Blending algorithm to use
|
|
19
|
+
* @param ratio - 0.0 = all hex1, 0.5 = equal mix, 1.0 = all hex2
|
|
20
|
+
*/
|
|
21
|
+
export declare function blendColors(hex1: string, hex2: string, mode: BlendingMode, ratio?: number): BlendResult;
|
|
22
|
+
//# sourceMappingURL=blending.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blending.d.ts","sourceRoot":"","sources":["../../src/blending/blending.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAiB,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAsB3E;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,YAAY,EAClB,KAAK,GAAE,MAAY,GAClB,WAAW,CAmCb"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Color Blending — Six algorithms for mixing two colors.
|
|
3
|
+
*
|
|
4
|
+
* Blending Modes:
|
|
5
|
+
* - RGB: Simple additive channel averaging
|
|
6
|
+
* - LAB: Perceptually uniform CIELAB blending
|
|
7
|
+
* - OKLAB: Modern perceptual (fixes LAB blue→purple issue)
|
|
8
|
+
* - RYB: Traditional artist's color wheel
|
|
9
|
+
* - HSL: Hue-Saturation-Lightness interpolation
|
|
10
|
+
* - Spectral: Kubelka-Munk physics simulation
|
|
11
|
+
*/
|
|
12
|
+
import { rgbToLab, labToRgb, rgbToOklab, oklabToRgb, rgbToRyb, rybToRgb, rgbToHsl, hslToRgb, rgbToReflectance, reflectanceToRgb, reflectanceToKS, ksToReflectance, rgbToHex, hexToRgb, } from './conversions.js';
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Public API
|
|
15
|
+
// ============================================================================
|
|
16
|
+
/**
|
|
17
|
+
* Blend two colors using the specified blending mode.
|
|
18
|
+
*
|
|
19
|
+
* @param hex1 - First color hex code (with or without #)
|
|
20
|
+
* @param hex2 - Second color hex code (with or without #)
|
|
21
|
+
* @param mode - Blending algorithm to use
|
|
22
|
+
* @param ratio - 0.0 = all hex1, 0.5 = equal mix, 1.0 = all hex2
|
|
23
|
+
*/
|
|
24
|
+
export function blendColors(hex1, hex2, mode, ratio = 0.5) {
|
|
25
|
+
const h1 = hex1.startsWith('#') ? hex1 : `#${hex1}`;
|
|
26
|
+
const h2 = hex2.startsWith('#') ? hex2 : `#${hex2}`;
|
|
27
|
+
const t = Math.max(0, Math.min(1, ratio));
|
|
28
|
+
// REFACTOR-005: local parser — no more dependency on all of core
|
|
29
|
+
const rgb1 = hexToRgb(h1);
|
|
30
|
+
const rgb2 = hexToRgb(h2);
|
|
31
|
+
let blendedRgb;
|
|
32
|
+
switch (mode) {
|
|
33
|
+
case 'rgb':
|
|
34
|
+
blendedRgb = blendRGB(rgb1, rgb2, t);
|
|
35
|
+
break;
|
|
36
|
+
case 'lab':
|
|
37
|
+
blendedRgb = blendLAB(rgb1, rgb2, t);
|
|
38
|
+
break;
|
|
39
|
+
case 'oklab':
|
|
40
|
+
blendedRgb = blendOKLAB(rgb1, rgb2, t);
|
|
41
|
+
break;
|
|
42
|
+
case 'ryb':
|
|
43
|
+
blendedRgb = blendRYB(rgb1, rgb2, t);
|
|
44
|
+
break;
|
|
45
|
+
case 'hsl':
|
|
46
|
+
blendedRgb = blendHSL(rgb1, rgb2, t);
|
|
47
|
+
break;
|
|
48
|
+
case 'spectral':
|
|
49
|
+
blendedRgb = blendSpectral(rgb1, rgb2, t);
|
|
50
|
+
break;
|
|
51
|
+
default:
|
|
52
|
+
blendedRgb = blendRGB(rgb1, rgb2, t);
|
|
53
|
+
}
|
|
54
|
+
return { hex: rgbToHex(blendedRgb), rgb: blendedRgb };
|
|
55
|
+
}
|
|
56
|
+
// ============================================================================
|
|
57
|
+
// Blend Implementations
|
|
58
|
+
// ============================================================================
|
|
59
|
+
function blendRGB(rgb1, rgb2, t) {
|
|
60
|
+
return {
|
|
61
|
+
r: Math.round(rgb1.r * (1 - t) + rgb2.r * t),
|
|
62
|
+
g: Math.round(rgb1.g * (1 - t) + rgb2.g * t),
|
|
63
|
+
b: Math.round(rgb1.b * (1 - t) + rgb2.b * t),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function blendLAB(rgb1, rgb2, t) {
|
|
67
|
+
const lab1 = rgbToLab(rgb1);
|
|
68
|
+
const lab2 = rgbToLab(rgb2);
|
|
69
|
+
const blended = {
|
|
70
|
+
l: lab1.l * (1 - t) + lab2.l * t,
|
|
71
|
+
a: lab1.a * (1 - t) + lab2.a * t,
|
|
72
|
+
b: lab1.b * (1 - t) + lab2.b * t,
|
|
73
|
+
};
|
|
74
|
+
return labToRgb(blended);
|
|
75
|
+
}
|
|
76
|
+
function blendOKLAB(rgb1, rgb2, t) {
|
|
77
|
+
const ok1 = rgbToOklab(rgb1);
|
|
78
|
+
const ok2 = rgbToOklab(rgb2);
|
|
79
|
+
return oklabToRgb({
|
|
80
|
+
L: ok1.L * (1 - t) + ok2.L * t,
|
|
81
|
+
a: ok1.a * (1 - t) + ok2.a * t,
|
|
82
|
+
b: ok1.b * (1 - t) + ok2.b * t,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function blendRYB(rgb1, rgb2, t) {
|
|
86
|
+
const ryb1 = rgbToRyb(rgb1);
|
|
87
|
+
const ryb2 = rgbToRyb(rgb2);
|
|
88
|
+
return rybToRgb({
|
|
89
|
+
r: ryb1.r * (1 - t) + ryb2.r * t,
|
|
90
|
+
y: ryb1.y * (1 - t) + ryb2.y * t,
|
|
91
|
+
b: ryb1.b * (1 - t) + ryb2.b * t,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
function blendHSL(rgb1, rgb2, t) {
|
|
95
|
+
const hsl1 = rgbToHsl(rgb1);
|
|
96
|
+
const hsl2 = rgbToHsl(rgb2);
|
|
97
|
+
// Shortest-arc hue interpolation
|
|
98
|
+
let hueDiff = hsl2.h - hsl1.h;
|
|
99
|
+
if (hueDiff > 180)
|
|
100
|
+
hueDiff -= 360;
|
|
101
|
+
if (hueDiff < -180)
|
|
102
|
+
hueDiff += 360;
|
|
103
|
+
let blendedH = hsl1.h + hueDiff * t;
|
|
104
|
+
if (blendedH < 0)
|
|
105
|
+
blendedH += 360;
|
|
106
|
+
if (blendedH >= 360)
|
|
107
|
+
blendedH -= 360;
|
|
108
|
+
const blended = {
|
|
109
|
+
h: blendedH,
|
|
110
|
+
s: hsl1.s * (1 - t) + hsl2.s * t,
|
|
111
|
+
l: hsl1.l * (1 - t) + hsl2.l * t,
|
|
112
|
+
};
|
|
113
|
+
return hslToRgb(blended);
|
|
114
|
+
}
|
|
115
|
+
function blendSpectral(rgb1, rgb2, t) {
|
|
116
|
+
const ref1 = rgbToReflectance(rgb1);
|
|
117
|
+
const ref2 = rgbToReflectance(rgb2);
|
|
118
|
+
return reflectanceToRgb({
|
|
119
|
+
r: kubelkaMunkMix(ref1.r, ref2.r, t),
|
|
120
|
+
g: kubelkaMunkMix(ref1.g, ref2.g, t),
|
|
121
|
+
b: kubelkaMunkMix(ref1.b, ref2.b, t),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
function kubelkaMunkMix(r1, r2, t) {
|
|
125
|
+
const ks1 = reflectanceToKS(r1);
|
|
126
|
+
const ks2 = reflectanceToKS(r2);
|
|
127
|
+
return ksToReflectance(ks1 * (1 - t) + ks2 * t);
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=blending.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blending.js","sourceRoot":"","sources":["../../src/blending/blending.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { RGB, LAB, HSL } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* RGB to CIELAB conversion.
|
|
4
|
+
* Exported for use in SVG generators that display LAB values.
|
|
5
|
+
*/
|
|
6
|
+
export declare function rgbToLab(rgb: RGB): LAB;
|
|
7
|
+
export declare function labToRgb(lab: LAB): RGB;
|
|
8
|
+
export declare function rgbToOklab(rgb: RGB): {
|
|
9
|
+
L: number;
|
|
10
|
+
a: number;
|
|
11
|
+
b: number;
|
|
12
|
+
};
|
|
13
|
+
export declare function oklabToRgb(oklab: {
|
|
14
|
+
L: number;
|
|
15
|
+
a: number;
|
|
16
|
+
b: number;
|
|
17
|
+
}): RGB;
|
|
18
|
+
export declare function rgbToRyb(rgb: RGB): {
|
|
19
|
+
r: number;
|
|
20
|
+
y: number;
|
|
21
|
+
b: number;
|
|
22
|
+
};
|
|
23
|
+
export declare function rybToRgb(ryb: {
|
|
24
|
+
r: number;
|
|
25
|
+
y: number;
|
|
26
|
+
b: number;
|
|
27
|
+
}): RGB;
|
|
28
|
+
export declare function rgbToHsl(rgb: RGB): HSL;
|
|
29
|
+
export declare function hslToRgb(hsl: HSL): RGB;
|
|
30
|
+
export declare function rgbToReflectance(rgb: RGB): {
|
|
31
|
+
r: number;
|
|
32
|
+
g: number;
|
|
33
|
+
b: number;
|
|
34
|
+
};
|
|
35
|
+
export declare function reflectanceToRgb(ref: {
|
|
36
|
+
r: number;
|
|
37
|
+
g: number;
|
|
38
|
+
b: number;
|
|
39
|
+
}): RGB;
|
|
40
|
+
export declare function reflectanceToKS(r: number): number;
|
|
41
|
+
export declare function ksToReflectance(ks: number): number;
|
|
42
|
+
/**
|
|
43
|
+
* Parse a hex color string into RGB channels.
|
|
44
|
+
*
|
|
45
|
+
* REFACTOR-005 (2026-07-18 audit): local implementation replacing the sole use
|
|
46
|
+
* of `@xivdyetools/core`'s ColorService — the entire core package (dye
|
|
47
|
+
* database, k-d tree, i18n) was a dependency for these ~10 lines. Matches
|
|
48
|
+
* core's strict behavior: throws on malformed input; accepts #RGB and #RRGGBB
|
|
49
|
+
* (leading # optional).
|
|
50
|
+
*/
|
|
51
|
+
export declare function hexToRgb(hex: string): RGB;
|
|
52
|
+
export declare function rgbToHex(rgb: RGB): string;
|
|
53
|
+
//# sourceMappingURL=conversions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversions.d.ts","sourceRoot":"","sources":["../../src/blending/conversions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAOhD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,CAyBtC;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,CA8BtC;AAMD,wBAAgB,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAwBxE;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,GAAG,CAuB1E;AAMD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAwBtE;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,GAAG,CA0BtE;AAMD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,CA8BtC;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,CA2BtC;AAMD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAE9E;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,GAAG,CAM9E;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAIjD;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAGlD;AAMD;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAiBzC;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAGzC"}
|