@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.
Files changed (156) hide show
  1. package/README.md +85 -67
  2. package/dist/blending/blending.d.ts +22 -0
  3. package/dist/blending/blending.d.ts.map +1 -0
  4. package/dist/blending/blending.js +129 -0
  5. package/dist/blending/blending.js.map +1 -0
  6. package/dist/blending/conversions.d.ts +53 -0
  7. package/dist/blending/conversions.d.ts.map +1 -0
  8. package/dist/blending/conversions.js +256 -0
  9. package/dist/blending/conversions.js.map +1 -0
  10. package/dist/blending/index.d.ts +8 -0
  11. package/dist/blending/index.d.ts.map +1 -0
  12. package/dist/blending/index.js +3 -0
  13. package/dist/blending/index.js.map +1 -0
  14. package/dist/blending/types.d.ts +36 -0
  15. package/dist/blending/types.d.ts.map +1 -0
  16. package/dist/blending/types.js +21 -0
  17. package/dist/blending/types.js.map +1 -0
  18. package/dist/config/band-calibration.d.ts +68 -0
  19. package/dist/config/band-calibration.d.ts.map +1 -0
  20. package/dist/config/band-calibration.js +196 -0
  21. package/dist/config/band-calibration.js.map +1 -0
  22. package/dist/config/band-vocabulary.d.ts +82 -0
  23. package/dist/config/band-vocabulary.d.ts.map +1 -0
  24. package/dist/config/band-vocabulary.js +117 -0
  25. package/dist/config/band-vocabulary.js.map +1 -0
  26. package/dist/config/consolidated-ids.js +2 -2
  27. package/dist/config/consolidated-ids.js.map +1 -1
  28. package/dist/config/dye-vocabulary.d.ts +45 -0
  29. package/dist/config/dye-vocabulary.d.ts.map +1 -0
  30. package/dist/config/dye-vocabulary.js +58 -0
  31. package/dist/config/dye-vocabulary.js.map +1 -0
  32. package/dist/config/facewear.d.ts +24 -0
  33. package/dist/config/facewear.d.ts.map +1 -0
  34. package/dist/config/facewear.js +35 -0
  35. package/dist/config/facewear.js.map +1 -0
  36. package/dist/config/learn-links.d.ts +70 -0
  37. package/dist/config/learn-links.d.ts.map +1 -0
  38. package/dist/config/learn-links.js +171 -0
  39. package/dist/config/learn-links.js.map +1 -0
  40. package/dist/config/product-links.d.ts +44 -0
  41. package/dist/config/product-links.d.ts.map +1 -0
  42. package/dist/config/product-links.js +44 -0
  43. package/dist/config/product-links.js.map +1 -0
  44. package/dist/constants/index.d.ts +14 -1
  45. package/dist/constants/index.d.ts.map +1 -1
  46. package/dist/constants/index.js +38 -22
  47. package/dist/constants/index.js.map +1 -1
  48. package/dist/data/character_colors/race_specific/hair_colors.json +1 -1
  49. package/dist/data/character_colors/race_specific/skin_colors.json +1 -1
  50. package/dist/data/dyes.json +1127 -0
  51. package/dist/data/facewear_colors.json +57 -0
  52. package/dist/data/locales/de.json +4 -50
  53. package/dist/data/locales/en.json +4 -50
  54. package/dist/data/locales/fr.json +4 -50
  55. package/dist/data/locales/ja.json +4 -50
  56. package/dist/data/locales/ko.json +4 -50
  57. package/dist/data/locales/zh.json +4 -50
  58. package/dist/data/presets.json +59 -301
  59. package/dist/index.d.ts +156 -17
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +114 -10
  62. package/dist/index.js.map +1 -1
  63. package/dist/services/APIService.d.ts +39 -62
  64. package/dist/services/APIService.d.ts.map +1 -1
  65. package/dist/services/APIService.js +156 -150
  66. package/dist/services/APIService.js.map +1 -1
  67. package/dist/services/CharacterColorService.d.ts +4 -36
  68. package/dist/services/CharacterColorService.d.ts.map +1 -1
  69. package/dist/services/CharacterColorService.js +57 -79
  70. package/dist/services/CharacterColorService.js.map +1 -1
  71. package/dist/services/ColorService.d.ts +57 -68
  72. package/dist/services/ColorService.d.ts.map +1 -1
  73. package/dist/services/ColorService.js +86 -94
  74. package/dist/services/ColorService.js.map +1 -1
  75. package/dist/services/DyeService.d.ts +11 -104
  76. package/dist/services/DyeService.d.ts.map +1 -1
  77. package/dist/services/DyeService.js +19 -157
  78. package/dist/services/DyeService.js.map +1 -1
  79. package/dist/services/LocalizationService.d.ts +48 -59
  80. package/dist/services/LocalizationService.d.ts.map +1 -1
  81. package/dist/services/LocalizationService.js +86 -95
  82. package/dist/services/LocalizationService.js.map +1 -1
  83. package/dist/services/PaletteService.d.ts +8 -9
  84. package/dist/services/PaletteService.d.ts.map +1 -1
  85. package/dist/services/PaletteService.js +10 -22
  86. package/dist/services/PaletteService.js.map +1 -1
  87. package/dist/services/PresetService.d.ts +2 -34
  88. package/dist/services/PresetService.d.ts.map +1 -1
  89. package/dist/services/PresetService.js +12 -59
  90. package/dist/services/PresetService.js.map +1 -1
  91. package/dist/services/chara/chara-models.d.ts +68 -0
  92. package/dist/services/chara/chara-models.d.ts.map +1 -0
  93. package/dist/services/chara/chara-models.js +87 -0
  94. package/dist/services/chara/chara-models.js.map +1 -0
  95. package/dist/services/chara/chara-parser.d.ts +95 -0
  96. package/dist/services/chara/chara-parser.d.ts.map +1 -0
  97. package/dist/services/chara/chara-parser.js +299 -0
  98. package/dist/services/chara/chara-parser.js.map +1 -0
  99. package/dist/services/chara/chara-resolver.d.ts +103 -0
  100. package/dist/services/chara/chara-resolver.d.ts.map +1 -0
  101. package/dist/services/chara/chara-resolver.js +233 -0
  102. package/dist/services/chara/chara-resolver.js.map +1 -0
  103. package/dist/services/color/ColorConverter.d.ts +112 -35
  104. package/dist/services/color/ColorConverter.d.ts.map +1 -1
  105. package/dist/services/color/ColorConverter.js +205 -89
  106. package/dist/services/color/ColorConverter.js.map +1 -1
  107. package/dist/services/color/ColorManipulator.d.ts +11 -0
  108. package/dist/services/color/ColorManipulator.d.ts.map +1 -1
  109. package/dist/services/color/ColorManipulator.js +24 -9
  110. package/dist/services/color/ColorManipulator.js.map +1 -1
  111. package/dist/services/color/ColorblindnessSimulator.d.ts +17 -0
  112. package/dist/services/color/ColorblindnessSimulator.d.ts.map +1 -1
  113. package/dist/services/color/ColorblindnessSimulator.js +57 -3
  114. package/dist/services/color/ColorblindnessSimulator.js.map +1 -1
  115. package/dist/services/color/SpectralMixer.d.ts +0 -34
  116. package/dist/services/color/SpectralMixer.d.ts.map +1 -1
  117. package/dist/services/color/SpectralMixer.js +0 -73
  118. package/dist/services/color/SpectralMixer.js.map +1 -1
  119. package/dist/services/dye/DyeDatabase.d.ts +5 -21
  120. package/dist/services/dye/DyeDatabase.d.ts.map +1 -1
  121. package/dist/services/dye/DyeDatabase.js +98 -130
  122. package/dist/services/dye/DyeDatabase.js.map +1 -1
  123. package/dist/services/dye/DyeSearch.d.ts +17 -31
  124. package/dist/services/dye/DyeSearch.d.ts.map +1 -1
  125. package/dist/services/dye/DyeSearch.js +45 -141
  126. package/dist/services/dye/DyeSearch.js.map +1 -1
  127. package/dist/services/dye/HarmonyGenerator.d.ts +11 -18
  128. package/dist/services/dye/HarmonyGenerator.d.ts.map +1 -1
  129. package/dist/services/dye/HarmonyGenerator.js +33 -38
  130. package/dist/services/dye/HarmonyGenerator.js.map +1 -1
  131. package/dist/services/localization/LocaleLoader.d.ts.map +1 -1
  132. package/dist/services/localization/LocaleLoader.js +0 -1
  133. package/dist/services/localization/LocaleLoader.js.map +1 -1
  134. package/dist/services/localization/TranslationProvider.d.ts +1 -42
  135. package/dist/services/localization/TranslationProvider.d.ts.map +1 -1
  136. package/dist/services/localization/TranslationProvider.js +4 -82
  137. package/dist/services/localization/TranslationProvider.js.map +1 -1
  138. package/dist/types/index.d.ts +39 -52
  139. package/dist/types/index.d.ts.map +1 -1
  140. package/dist/types/index.js +50 -10
  141. package/dist/types/index.js.map +1 -1
  142. package/dist/utils/index.d.ts +36 -123
  143. package/dist/utils/index.d.ts.map +1 -1
  144. package/dist/utils/index.js +54 -413
  145. package/dist/utils/index.js.map +1 -1
  146. package/dist/utils/kd-tree.d.ts +0 -4
  147. package/dist/utils/kd-tree.d.ts.map +1 -1
  148. package/dist/utils/kd-tree.js +0 -6
  149. package/dist/utils/kd-tree.js.map +1 -1
  150. package/package.json +24 -15
  151. package/dist/data/character_colors/index.json +0 -40
  152. package/dist/data/colors_xiv.json +0 -3538
  153. package/dist/version.d.ts +0 -11
  154. package/dist/version.d.ts.map +0 -1
  155. package/dist/version.js +0 -11
  156. package/dist/version.js.map +0 -1
@@ -0,0 +1,82 @@
1
+ /**
2
+ * The 5.0 band vocabulary — calibrated per-method tier boundaries.
3
+ *
4
+ * Confirmed 2026-08-07 (`Band Calibration.dc.html`): the non-default methods
5
+ * take empirical accuracy-optimal cuts against ΔE2000's settled tiers,
6
+ * rounded to display precision and scored on rounded values. The numbers here
7
+ * are generated by `scripts/calibrate-bands.ts` (algorithm in
8
+ * `band-calibration.ts`) and guarded by a parity test — do not hand-edit;
9
+ * re-run the script if `dyes.json` changes.
10
+ *
11
+ * Three standing rules, whatever the method:
12
+ * 1. Print the method wherever a tier or verdict appears.
13
+ * 2. Never compare a tier across methods.
14
+ * 3. Only ΔE2000's bands follow the user's match line — every other method's
15
+ * bands are fixed, and copy must say so (use
16
+ * {@link classifyBandTierWithCuts} for the ΔE2000-with-user-slider case).
17
+ *
18
+ * Notes carried from the study:
19
+ * - ΔEOK prints raw (dp 3); a ×100 display unit converts exactly (same cuts).
20
+ * - DISTINGUISH % derives exactly from RGB DIST (identical ranks); its bands
21
+ * are computed from RGB DIST's cuts, never calibrated separately. Integer
22
+ * rounding creates ties — orderings need a sort fallback and ties badge TIE.
23
+ * - RATIO is not a distance (lightness only) and never joins the tier
24
+ * vocabulary; its calibrated cuts exist only for Accessibility + Comparison,
25
+ * with the Accessibility top band anchored at 3:1 (WCAG 1.4.11). A first
26
+ * band of 1.00 is literal: that tier is unreachable through lightness alone.
27
+ */
28
+ /** Contexts a band set applies to (per-tool subsets of one vocabulary). */
29
+ export type BandContext = 'match' | 'harmony' | 'separation';
30
+ /** Distance-like methods carrying tier bands. */
31
+ export type BandMethod = 'ciede2000' | 'oklab' | 'cie76' | 'redmean' | 'rgb' | 'distinguish';
32
+ /** Tier index: 0 = best band (below first cut) … 3 = beyond the last cut. */
33
+ export type BandTier = 0 | 1 | 2 | 3;
34
+ export interface MethodBandSet {
35
+ /** Ascending tier boundaries at display precision */
36
+ cuts: readonly [number, number, number];
37
+ /** Display precision (decimal places) — tiers score on the displayed value */
38
+ dp: number;
39
+ }
40
+ /** Display precision per method (identifiers, not quantities — never localise). */
41
+ export declare const BAND_METHOD_DP: Record<BandMethod, number>;
42
+ /** Derive DISTINGUISH % cuts from RGB DIST cuts (the one legal derivation). */
43
+ export declare function deriveDistinguishCuts(rgbdistCuts: readonly [number, number, number]): [number, number, number];
44
+ /**
45
+ * The calibrated band vocabulary. ΔE2000 rows are the settled ground truth
46
+ * (MATCH 5/10/20 · HARMONY 6/12/20 · SEPARATION 8/15/30 ascending — the UI
47
+ * reads SEPARATION descending, 30/15/8, high = clear).
48
+ */
49
+ export declare const BAND_VOCABULARY: Record<BandContext, Record<BandMethod, MethodBandSet>>;
50
+ /**
51
+ * RATIO (WCAG contrast) bands — Accessibility Checker and Dye Comparison
52
+ * only. Not a distance; prints last after a rule; per-tool cuts and polarity;
53
+ * ordering still sorts ascending. dp 2.
54
+ */
55
+ export declare const RATIO_BANDS: {
56
+ /** Calibrated vs MATCH tiers. All 1.00: no lightness cut separates the
57
+ * lower tiers at all on real pairs — a finding about RATIO, not a bug. */
58
+ readonly comparison: {
59
+ readonly cuts: readonly [1, 1, 1];
60
+ readonly dp: 2;
61
+ };
62
+ /** Calibrated vs SEPARATION tiers on the pooled lens corpus, top band
63
+ * anchored at 3:1 (the WCAG 1.4.11 figure). */
64
+ readonly accessibility: {
65
+ readonly cuts: readonly [1, 1.29, 3];
66
+ readonly dp: 2;
67
+ };
68
+ };
69
+ /** Round a value to a method's display precision (tier-on-displayed-value). */
70
+ export declare function roundToBandDisplay(value: number, method: BandMethod): number;
71
+ /**
72
+ * Classify a measured value against explicit cuts, scoring on the
73
+ * display-rounded value. Use this directly for ΔE2000 when the user's match
74
+ * line has moved the MATCH cuts; every other method's cuts are fixed.
75
+ */
76
+ export declare function classifyBandTierWithCuts(value: number, cuts: readonly [number, number, number], dp: number): BandTier;
77
+ /**
78
+ * Classify a measured value into its band tier for a method + context.
79
+ * The value must be in the method's native unit (ΔEOK raw, not ×100).
80
+ */
81
+ export declare function classifyBandTier(value: number, method: BandMethod, context: BandContext): BandTier;
82
+ //# sourceMappingURL=band-vocabulary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"band-vocabulary.d.ts","sourceRoot":"","sources":["../../src/config/band-vocabulary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,2EAA2E;AAC3E,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,SAAS,GAAG,YAAY,CAAC;AAE7D,iDAAiD;AACjD,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,KAAK,GAAG,aAAa,CAAC;AAE7F,6EAA6E;AAC7E,MAAM,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAErC,MAAM,WAAW,aAAa;IAC5B,qDAAqD;IACrD,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,8EAA8E;IAC9E,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,mFAAmF;AACnF,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAOrD,CAAC;AAEF,+EAA+E;AAC/E,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAC7C,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAM1B;AAYD;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,CAyBlF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,WAAW;IACtB;+EAC2E;;;;;IAE3E;oDACgD;;;;;CAExC,CAAC;AAEX,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAG5E;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACvC,EAAE,EAAE,MAAM,GACT,QAAQ,CAIV;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,WAAW,GACnB,QAAQ,CAGV"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * The 5.0 band vocabulary — calibrated per-method tier boundaries.
3
+ *
4
+ * Confirmed 2026-08-07 (`Band Calibration.dc.html`): the non-default methods
5
+ * take empirical accuracy-optimal cuts against ΔE2000's settled tiers,
6
+ * rounded to display precision and scored on rounded values. The numbers here
7
+ * are generated by `scripts/calibrate-bands.ts` (algorithm in
8
+ * `band-calibration.ts`) and guarded by a parity test — do not hand-edit;
9
+ * re-run the script if `dyes.json` changes.
10
+ *
11
+ * Three standing rules, whatever the method:
12
+ * 1. Print the method wherever a tier or verdict appears.
13
+ * 2. Never compare a tier across methods.
14
+ * 3. Only ΔE2000's bands follow the user's match line — every other method's
15
+ * bands are fixed, and copy must say so (use
16
+ * {@link classifyBandTierWithCuts} for the ΔE2000-with-user-slider case).
17
+ *
18
+ * Notes carried from the study:
19
+ * - ΔEOK prints raw (dp 3); a ×100 display unit converts exactly (same cuts).
20
+ * - DISTINGUISH % derives exactly from RGB DIST (identical ranks); its bands
21
+ * are computed from RGB DIST's cuts, never calibrated separately. Integer
22
+ * rounding creates ties — orderings need a sort fallback and ties badge TIE.
23
+ * - RATIO is not a distance (lightness only) and never joins the tier
24
+ * vocabulary; its calibrated cuts exist only for Accessibility + Comparison,
25
+ * with the Accessibility top band anchored at 3:1 (WCAG 1.4.11). A first
26
+ * band of 1.00 is literal: that tier is unreachable through lightness alone.
27
+ */
28
+ import { COLOR_DISTANCE_MAX } from '../constants/index.js';
29
+ /** Display precision per method (identifiers, not quantities — never localise). */
30
+ export const BAND_METHOD_DP = {
31
+ ciede2000: 1,
32
+ oklab: 3,
33
+ cie76: 1,
34
+ redmean: 1,
35
+ rgb: 1,
36
+ distinguish: 0,
37
+ };
38
+ /** Derive DISTINGUISH % cuts from RGB DIST cuts (the one legal derivation). */
39
+ export function deriveDistinguishCuts(rgbdistCuts) {
40
+ return rgbdistCuts.map((v) => Math.round((v / COLOR_DISTANCE_MAX) * 100));
41
+ }
42
+ function bandSet(cuts, method) {
43
+ return { cuts, dp: BAND_METHOD_DP[method] };
44
+ }
45
+ const RGBDIST_CUTS = {
46
+ match: [8.3, 18.9, 55.5],
47
+ harmony: [11.2, 26.1, 55.5],
48
+ separation: [34.7, 58.9, 129.9],
49
+ };
50
+ /**
51
+ * The calibrated band vocabulary. ΔE2000 rows are the settled ground truth
52
+ * (MATCH 5/10/20 · HARMONY 6/12/20 · SEPARATION 8/15/30 ascending — the UI
53
+ * reads SEPARATION descending, 30/15/8, high = clear).
54
+ */
55
+ export const BAND_VOCABULARY = {
56
+ match: {
57
+ ciede2000: bandSet([5, 10, 20], 'ciede2000'),
58
+ oklab: bandSet([0.017, 0.04, 0.107], 'oklab'),
59
+ cie76: bandSet([5.4, 12.6, 26.2], 'cie76'),
60
+ redmean: bandSet([13.9, 31.9, 91.1], 'redmean'),
61
+ rgb: bandSet(RGBDIST_CUTS.match, 'rgb'),
62
+ distinguish: bandSet(deriveDistinguishCuts(RGBDIST_CUTS.match), 'distinguish'),
63
+ },
64
+ harmony: {
65
+ ciede2000: bandSet([6, 12, 20], 'ciede2000'),
66
+ oklab: bandSet([0.02, 0.053, 0.107], 'oklab'),
67
+ cie76: bandSet([6.7, 14.5, 26.2], 'cie76'),
68
+ redmean: bandSet([16.5, 44.4, 91.1], 'redmean'),
69
+ rgb: bandSet(RGBDIST_CUTS.harmony, 'rgb'),
70
+ distinguish: bandSet(deriveDistinguishCuts(RGBDIST_CUTS.harmony), 'distinguish'),
71
+ },
72
+ separation: {
73
+ ciede2000: bandSet([8, 15, 30], 'ciede2000'),
74
+ oklab: bandSet([0.062, 0.103, 0.252], 'oklab'),
75
+ cie76: bandSet([10.4, 19.3, 38.4], 'cie76'),
76
+ redmean: bandSet([54, 102, 222], 'redmean'),
77
+ rgb: bandSet(RGBDIST_CUTS.separation, 'rgb'),
78
+ distinguish: bandSet(deriveDistinguishCuts(RGBDIST_CUTS.separation), 'distinguish'),
79
+ },
80
+ };
81
+ /**
82
+ * RATIO (WCAG contrast) bands — Accessibility Checker and Dye Comparison
83
+ * only. Not a distance; prints last after a rule; per-tool cuts and polarity;
84
+ * ordering still sorts ascending. dp 2.
85
+ */
86
+ export const RATIO_BANDS = {
87
+ /** Calibrated vs MATCH tiers. All 1.00: no lightness cut separates the
88
+ * lower tiers at all on real pairs — a finding about RATIO, not a bug. */
89
+ comparison: { cuts: [1, 1, 1], dp: 2 },
90
+ /** Calibrated vs SEPARATION tiers on the pooled lens corpus, top band
91
+ * anchored at 3:1 (the WCAG 1.4.11 figure). */
92
+ accessibility: { cuts: [1, 1.29, 3], dp: 2 },
93
+ };
94
+ /** Round a value to a method's display precision (tier-on-displayed-value). */
95
+ export function roundToBandDisplay(value, method) {
96
+ const f = Math.pow(10, BAND_METHOD_DP[method]);
97
+ return Math.round(value * f) / f;
98
+ }
99
+ /**
100
+ * Classify a measured value against explicit cuts, scoring on the
101
+ * display-rounded value. Use this directly for ΔE2000 when the user's match
102
+ * line has moved the MATCH cuts; every other method's cuts are fixed.
103
+ */
104
+ export function classifyBandTierWithCuts(value, cuts, dp) {
105
+ const f = Math.pow(10, dp);
106
+ const v = Math.round(value * f) / f;
107
+ return v < cuts[0] ? 0 : v < cuts[1] ? 1 : v < cuts[2] ? 2 : 3;
108
+ }
109
+ /**
110
+ * Classify a measured value into its band tier for a method + context.
111
+ * The value must be in the method's native unit (ΔEOK raw, not ×100).
112
+ */
113
+ export function classifyBandTier(value, method, context) {
114
+ const { cuts, dp } = BAND_VOCABULARY[context][method];
115
+ return classifyBandTierWithCuts(value, cuts, dp);
116
+ }
117
+ //# sourceMappingURL=band-vocabulary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"band-vocabulary.js","sourceRoot":"","sources":["../../src/config/band-vocabulary.ts"],"names":[],"mappings":"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"}
@@ -40,8 +40,8 @@ export const CONSOLIDATED_DYES = {
40
40
  zh: '追加染剂1',
41
41
  },
42
42
  acquisition: 'The Firmament',
43
- price: 1000,
44
- currency: "Sky Builders' Scrips",
43
+ price: 100,
44
+ currency: 'Skybuilders Scrips',
45
45
  },
46
46
  C: {
47
47
  itemID: CONSOLIDATED_IDS.C,
@@ -1 +1 @@
1
- {"version":3,"file":"consolidated-ids.js","sourceRoot":"","sources":["../../src/config/consolidated-ids.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA4BH,MAAM,CAAC,MAAM,gBAAgB,GAA6C;IACxE,CAAC,EAAE,KAAK,EAAE,qEAAqE;IAC/E,CAAC,EAAE,KAAK,EAAE,wFAAwF;IAClG,CAAC,EAAE,KAAK,EAAE,4FAA4F;CACvG,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAA+C;IAC3E,CAAC,EAAE;QACD,MAAM,EAAE,gBAAgB,CAAC,CAAC;QAC1B,KAAK,EAAE;YACL,EAAE,EAAE,uBAAuB;YAC3B,EAAE,EAAE,eAAe;YACnB,EAAE,EAAE,qBAAqB;YACzB,EAAE,EAAE,mBAAmB;YACvB,EAAE,EAAE,WAAW;YACf,EAAE,EAAE,MAAM;SACX;QACD,WAAW,EAAE,YAAY;QACzB,KAAK,EAAE,GAAG;QACV,QAAQ,EAAE,KAAK;KAChB;IACD,CAAC,EAAE;QACD,MAAM,EAAE,gBAAgB,CAAC,CAAC;QAC1B,KAAK,EAAE;YACL,EAAE,EAAE,sBAAsB;YAC1B,EAAE,EAAE,mBAAmB;YACvB,EAAE,EAAE,mBAAmB;YACvB,EAAE,EAAE,4BAA4B;YAChC,EAAE,EAAE,aAAa;YACjB,EAAE,EAAE,OAAO;SACZ;QACD,WAAW,EAAE,eAAe;QAC5B,KAAK,EAAE,IAAI;QACX,QAAQ,EAAE,sBAAsB;KACjC;IACD,CAAC,EAAE;QACD,MAAM,EAAE,gBAAgB,CAAC,CAAC;QAC1B,KAAK,EAAE;YACL,EAAE,EAAE,sBAAsB;YAC1B,EAAE,EAAE,mBAAmB;YACvB,EAAE,EAAE,mBAAmB;YACvB,EAAE,EAAE,4BAA4B;YAChC,EAAE,EAAE,aAAa;YACjB,EAAE,EAAE,OAAO;SACZ;QACD,WAAW,EAAE,oBAAoB;QACjC,KAAK,EAAE,GAAG;QACV,QAAQ,EAAE,cAAc;KACzB;CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO,CACL,gBAAgB,CAAC,CAAC,KAAK,IAAI;QAC3B,gBAAgB,CAAC,CAAC,KAAK,IAAI;QAC3B,gBAAgB,CAAC,CAAC,KAAK,IAAI,CAC5B,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,GAG/B;IACC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,WAAW;IAClD,IAAI,CAAC,GAAG,CAAC,iBAAiB;QAAE,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,wBAAwB;IACvE,IAAI,CAAC,qBAAqB,EAAE;QAAE,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,qBAAqB;IACtE,OAAO,gBAAgB,CAAC,GAAG,CAAC,iBAAiB,CAAE,CAAC;AAClD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAuB,EAAE,MAAkB;IAChF,MAAM,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC;IAC5C,OAAO,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;AACnC,CAAC"}
1
+ {"version":3,"file":"consolidated-ids.js","sourceRoot":"","sources":["../../src/config/consolidated-ids.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA4BH,MAAM,CAAC,MAAM,gBAAgB,GAA6C;IACxE,CAAC,EAAE,KAAK,EAAE,qEAAqE;IAC/E,CAAC,EAAE,KAAK,EAAE,wFAAwF;IAClG,CAAC,EAAE,KAAK,EAAE,4FAA4F;CACvG,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAA+C;IAC3E,CAAC,EAAE;QACD,MAAM,EAAE,gBAAgB,CAAC,CAAC;QAC1B,KAAK,EAAE;YACL,EAAE,EAAE,uBAAuB;YAC3B,EAAE,EAAE,eAAe;YACnB,EAAE,EAAE,qBAAqB;YACzB,EAAE,EAAE,mBAAmB;YACvB,EAAE,EAAE,WAAW;YACf,EAAE,EAAE,MAAM;SACX;QACD,WAAW,EAAE,YAAY;QACzB,KAAK,EAAE,GAAG;QACV,QAAQ,EAAE,KAAK;KAChB;IACD,CAAC,EAAE;QACD,MAAM,EAAE,gBAAgB,CAAC,CAAC;QAC1B,KAAK,EAAE;YACL,EAAE,EAAE,sBAAsB;YAC1B,EAAE,EAAE,mBAAmB;YACvB,EAAE,EAAE,mBAAmB;YACvB,EAAE,EAAE,4BAA4B;YAChC,EAAE,EAAE,aAAa;YACjB,EAAE,EAAE,OAAO;SACZ;QACD,WAAW,EAAE,eAAe;QAC5B,KAAK,EAAE,GAAG;QACV,QAAQ,EAAE,oBAAoB;KAC/B;IACD,CAAC,EAAE;QACD,MAAM,EAAE,gBAAgB,CAAC,CAAC;QAC1B,KAAK,EAAE;YACL,EAAE,EAAE,sBAAsB;YAC1B,EAAE,EAAE,mBAAmB;YACvB,EAAE,EAAE,mBAAmB;YACvB,EAAE,EAAE,4BAA4B;YAChC,EAAE,EAAE,aAAa;YACjB,EAAE,EAAE,OAAO;SACZ;QACD,WAAW,EAAE,oBAAoB;QACjC,KAAK,EAAE,GAAG;QACV,QAAQ,EAAE,cAAc;KACzB;CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO,CACL,gBAAgB,CAAC,CAAC,KAAK,IAAI;QAC3B,gBAAgB,CAAC,CAAC,KAAK,IAAI;QAC3B,gBAAgB,CAAC,CAAC,KAAK,IAAI,CAC5B,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,GAG/B;IACC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,WAAW;IAClD,IAAI,CAAC,GAAG,CAAC,iBAAiB;QAAE,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,wBAAwB;IACvE,IAAI,CAAC,qBAAqB,EAAE;QAAE,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,qBAAqB;IACtE,OAAO,gBAAgB,CAAC,GAAG,CAAC,iBAAiB,CAAE,CAAC;AAClD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAuB,EAAE,MAAkB;IAChF,MAAM,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC;IAC5C,OAAO,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;AACnC,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Closed vocabularies for the dye database.
3
+ *
4
+ * Single source of truth for the category/acquisition/currency value sets and
5
+ * the acquisition → (price, currency) coupling. Ported from the retired
6
+ * `apps/maintainer` tool during the Monorepo 2.0 consolidation — but corrected:
7
+ * the maintainer's lists had drifted badly (8 of its 10 acquisition values
8
+ * appeared in zero dyes while 3 real ones were missing).
9
+ *
10
+ * These constants are enforced against `colors_xiv.json` by
11
+ * `__tests__/dye-vocabulary.test.ts`, which replaces the maintainer's
12
+ * validation role (duplicate-ID checks, closed-vocabulary checks) with CI.
13
+ *
14
+ * See docs/research/monorepo-2.0/01-dye-data-format.md — under schema v2 the
15
+ * per-entry `price`/`currency` fields are dropped entirely in favor of
16
+ * `ACQUISITION_META`.
17
+ */
18
+ /** Every category value present in the dye database, in display order. */
19
+ export declare const DYE_CATEGORIES: readonly ["Neutral", "Reds", "Browns", "Yellows", "Greens", "Blues", "Purples", "Special"];
20
+ export type DyeCategory = (typeof DYE_CATEGORIES)[number];
21
+ /** Every acquisition source present in the dye database. */
22
+ export declare const DYE_ACQUISITIONS: readonly ["Dye Vendor", "The Firmament", "Cosmic Exploration", "Venture Coffers"];
23
+ export type DyeAcquisition = (typeof DYE_ACQUISITIONS)[number];
24
+ export interface AcquisitionMeta {
25
+ /** Vendor price in the acquisition's currency. */
26
+ price: number;
27
+ /** Currency name. */
28
+ currency: string;
29
+ }
30
+ /**
31
+ * The acquisition → (price, currency) coupling. Exactly one pair per
32
+ * acquisition value — verified 125/125 against the dye database. Under
33
+ * schema v2 the per-entry price/currency fields no longer exist in the data
34
+ * file; `DyeDatabase.initialize()` derives `cost`/`currency` from this table.
35
+ */
36
+ export declare const ACQUISITION_META: Record<DyeAcquisition, AcquisitionMeta>;
37
+ /**
38
+ * Stain-sheet gloss rows (`IsMetallic = true` in the game's Stain sheet) —
39
+ * the authoritative metallic set (16 stains). Note this is NOT the same as
40
+ * `name.startsWith('Metallic')` (14): the game marks Gunmetal Black (92) and
41
+ * Pearl White (93) as metallic/gloss too. Decided 2026-07-30: the metallic
42
+ * filter means gloss (research/monorepo-2.0/01 §6 #5).
43
+ */
44
+ export declare const METALLIC_STAIN_IDS: ReadonlySet<number>;
45
+ //# sourceMappingURL=dye-vocabulary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dye-vocabulary.d.ts","sourceRoot":"","sources":["../../src/config/dye-vocabulary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,0EAA0E;AAC1E,eAAO,MAAM,cAAc,4FASjB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D,4DAA4D;AAC5D,eAAO,MAAM,gBAAgB,mFAKnB,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/D,MAAM,WAAW,eAAe;IAC9B,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,cAAc,EAAE,eAAe,CAKpE,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAEjD,CAAC"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Closed vocabularies for the dye database.
3
+ *
4
+ * Single source of truth for the category/acquisition/currency value sets and
5
+ * the acquisition → (price, currency) coupling. Ported from the retired
6
+ * `apps/maintainer` tool during the Monorepo 2.0 consolidation — but corrected:
7
+ * the maintainer's lists had drifted badly (8 of its 10 acquisition values
8
+ * appeared in zero dyes while 3 real ones were missing).
9
+ *
10
+ * These constants are enforced against `colors_xiv.json` by
11
+ * `__tests__/dye-vocabulary.test.ts`, which replaces the maintainer's
12
+ * validation role (duplicate-ID checks, closed-vocabulary checks) with CI.
13
+ *
14
+ * See docs/research/monorepo-2.0/01-dye-data-format.md — under schema v2 the
15
+ * per-entry `price`/`currency` fields are dropped entirely in favor of
16
+ * `ACQUISITION_META`.
17
+ */
18
+ /** Every category value present in the dye database, in display order. */
19
+ export const DYE_CATEGORIES = [
20
+ 'Neutral',
21
+ 'Reds',
22
+ 'Browns',
23
+ 'Yellows',
24
+ 'Greens',
25
+ 'Blues',
26
+ 'Purples',
27
+ 'Special',
28
+ ];
29
+ /** Every acquisition source present in the dye database. */
30
+ export const DYE_ACQUISITIONS = [
31
+ 'Dye Vendor',
32
+ 'The Firmament',
33
+ 'Cosmic Exploration',
34
+ 'Venture Coffers',
35
+ ];
36
+ /**
37
+ * The acquisition → (price, currency) coupling. Exactly one pair per
38
+ * acquisition value — verified 125/125 against the dye database. Under
39
+ * schema v2 the per-entry price/currency fields no longer exist in the data
40
+ * file; `DyeDatabase.initialize()` derives `cost`/`currency` from this table.
41
+ */
42
+ export const ACQUISITION_META = {
43
+ 'Dye Vendor': { price: 216, currency: 'Gil' },
44
+ 'The Firmament': { price: 100, currency: 'Skybuilders Scrips' },
45
+ 'Cosmic Exploration': { price: 600, currency: 'Cosmocredits' },
46
+ 'Venture Coffers': { price: 1, currency: 'Venture Coffer' },
47
+ };
48
+ /**
49
+ * Stain-sheet gloss rows (`IsMetallic = true` in the game's Stain sheet) —
50
+ * the authoritative metallic set (16 stains). Note this is NOT the same as
51
+ * `name.startsWith('Metallic')` (14): the game marks Gunmetal Black (92) and
52
+ * Pearl White (93) as metallic/gloss too. Decided 2026-07-30: the metallic
53
+ * filter means gloss (research/monorepo-2.0/01 §6 #5).
54
+ */
55
+ export const METALLIC_STAIN_IDS = new Set([
56
+ 92, 93, 94, 112, 113, 114, 115, 116, 117, 118, 119, 120, 122, 123, 124, 125,
57
+ ]);
58
+ //# sourceMappingURL=dye-vocabulary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dye-vocabulary.js","sourceRoot":"","sources":["../../src/config/dye-vocabulary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,0EAA0E;AAC1E,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,SAAS;IACT,MAAM;IACN,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,OAAO;IACP,SAAS;IACT,SAAS;CACD,CAAC;AAIX,4DAA4D;AAC5D,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,YAAY;IACZ,eAAe;IACf,oBAAoB;IACpB,iBAAiB;CACT,CAAC;AAWX;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAA4C;IACvE,YAAY,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE;IAC7C,eAAe,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,oBAAoB,EAAE;IAC/D,oBAAoB,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,cAAc,EAAE;IAC9D,iBAAiB,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,gBAAgB,EAAE;CAC5D,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAwB,IAAI,GAAG,CAAC;IAC7D,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;CAC5E,CAAC,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Facewear colors — the 11 glasses-color entries split out of the dye
3
+ * database in schema v2 (Monorepo 2.0; docs/research/monorepo-2.0/01 §3).
4
+ *
5
+ * They are not stains: no stainID, no market presence, no Stain-sheet row.
6
+ */
7
+ import type { FacewearColor } from '@xivdyetools/types';
8
+ export declare const facewearColors: readonly FacewearColor[];
9
+ /**
10
+ * Frozen mapping of the pre-v2 synthetic negative itemIDs to facewear slugs.
11
+ *
12
+ * Before schema v2, `DyeDatabase.initialize()` assigned each Facewear entry
13
+ * `-(1000 + Σ charCode(name))`. Those IDs escaped into serialized data
14
+ * (api-worker's public negative-ID lookups, potentially localStorage). This
15
+ * table is FROZEN — computed once from the names as they existed at the
16
+ * split (2026-07-31) and must never be regenerated from live data, or a
17
+ * rename would silently orphan persisted references (research/monorepo-2.0/02).
18
+ */
19
+ export declare const LEGACY_FACEWEAR_ITEM_IDS: Readonly<Record<number, string>>;
20
+ /** Look up a facewear color by its slug id. */
21
+ export declare function getFacewearColor(id: string): FacewearColor | null;
22
+ /** Resolve a pre-v2 synthetic negative itemID to its facewear color. */
23
+ export declare function getFacewearColorByLegacyItemID(legacyId: number): FacewearColor | null;
24
+ //# sourceMappingURL=facewear.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"facewear.d.ts","sourceRoot":"","sources":["../../src/config/facewear.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGxD,eAAO,MAAM,cAAc,EAAE,SAAS,aAAa,EAAiB,CAAC;AAErE;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAYrE,CAAC;AAEF,+CAA+C;AAC/C,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAEjE;AAED,wEAAwE;AACxE,wBAAgB,8BAA8B,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAGrF"}
@@ -0,0 +1,35 @@
1
+ import facewearData from '../data/facewear_colors.json' with { type: 'json' };
2
+ export const facewearColors = facewearData;
3
+ /**
4
+ * Frozen mapping of the pre-v2 synthetic negative itemIDs to facewear slugs.
5
+ *
6
+ * Before schema v2, `DyeDatabase.initialize()` assigned each Facewear entry
7
+ * `-(1000 + Σ charCode(name))`. Those IDs escaped into serialized data
8
+ * (api-worker's public negative-ID lookups, potentially localStorage). This
9
+ * table is FROZEN — computed once from the names as they existed at the
10
+ * split (2026-07-31) and must never be regenerated from live data, or a
11
+ * rename would silently orphan persisted references (research/monorepo-2.0/02).
12
+ */
13
+ export const LEGACY_FACEWEAR_ITEM_IDS = {
14
+ [-1629]: 'silver',
15
+ [-1390]: 'gold',
16
+ [-1477]: 'black',
17
+ [-1513]: 'white',
18
+ [-1407]: 'grey',
19
+ [-1283]: 'red',
20
+ [-1392]: 'blue',
21
+ [-1497]: 'green',
22
+ [-1507]: 'brass',
23
+ [-1632]: 'purple',
24
+ [-1520]: 'brown',
25
+ };
26
+ /** Look up a facewear color by its slug id. */
27
+ export function getFacewearColor(id) {
28
+ return facewearColors.find((f) => f.id === id) ?? null;
29
+ }
30
+ /** Resolve a pre-v2 synthetic negative itemID to its facewear color. */
31
+ export function getFacewearColorByLegacyItemID(legacyId) {
32
+ const slug = LEGACY_FACEWEAR_ITEM_IDS[legacyId];
33
+ return slug ? getFacewearColor(slug) : null;
34
+ }
35
+ //# sourceMappingURL=facewear.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"facewear.js","sourceRoot":"","sources":["../../src/config/facewear.ts"],"names":[],"mappings":"AAOA,OAAO,YAAY,MAAM,8BAA8B,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAE9E,MAAM,CAAC,MAAM,cAAc,GAA6B,YAAY,CAAC;AAErE;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAqC;IACxE,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ;IACjB,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM;IACf,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO;IAChB,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO;IAChB,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM;IACf,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK;IACd,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM;IACf,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO;IAChB,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO;IAChB,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ;IACjB,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO;CACjB,CAAC;AAEF,+CAA+C;AAC/C,MAAM,UAAU,gBAAgB,CAAC,EAAU;IACzC,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,IAAI,CAAC;AACzD,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,8BAA8B,CAAC,QAAgB;IAC7D,MAAM,IAAI,GAAG,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IAChD,OAAO,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * /manual topic roster + learn-more link table — shared data for every
3
+ * surface (web MetricHelp rows, bot /manual embeds, og-worker redirect page).
4
+ *
5
+ * Per the confirmed 5.0 rules (design register, cross-cutting):
6
+ * - Authority order when sourcing: clinical body → medical portal →
7
+ * encyclopaedia. Read the target, not its name.
8
+ * - **A missing URL degrades to no link, never the English one.**
9
+ * - Embeds print authority + host, never the path; web `<a>`s still name the
10
+ * authority.
11
+ * - The lead sentence and its tail are authored together per locale (JA
12
+ * `をご覧ください`; KO takes no tail — position-dependent). Those live in
13
+ * the locale string tables, not here.
14
+ * - Every URL here passed a liveness check on 2026-08-07. Two of five had
15
+ * already moved once before that — keep the liveness test in CI-reachable
16
+ * form and treat a dead link as an absent link at render time.
17
+ *
18
+ * Roster decisions:
19
+ * - Colour Vision: EN = NEI (clinical body) · DE = Portal der Augenmedizin
20
+ * (medical portal) · FR = Wikipédia *Daltonisme* (encyclopaedia; no
21
+ * endorsed FR clinical page) · JA = 日本眼科医会 (the JA copy names
22
+ * achromatopsia as separate, not a fourth 色覚異常) · KO = KDCA 국가건강정보포털.
23
+ * **ZH is deliberately absent** — blocked on a Simplified-Chinese reader.
24
+ * - Contrast: cite WCAG 1.4.11 in all six locales, but **link only en/fr/zh**
25
+ * (the W3C-authorized translations). DE's endorsed 2.0 translation lacks the
26
+ * criterion; KO's translation is unofficial http; JA's waic.jp needs its own
27
+ * check before it can join.
28
+ * - Matching Methods: our own docs — no localised authority exists.
29
+ * - Spectrum & Prices: Lodestone **by game region, not locale**.
30
+ * - Image Matching Tips and Character File link nothing.
31
+ */
32
+ import type { LocaleCode } from '@xivdyetools/types';
33
+ /** Manual topic identifiers — stored choice values, verbatim across locales. */
34
+ export type ManualTopicId = 'match_image' | 'color_vision' | 'contrast' | 'matching_methods' | 'spectrum_prices' | 'character_file';
35
+ /** FFXIV Lodestone regions (per-region hosts, not per-locale). */
36
+ export type LodestoneRegion = 'na' | 'eu' | 'jp' | 'de' | 'fr';
37
+ export interface LearnLink {
38
+ /** The authority to name in UI (never print the URL path) */
39
+ authority: string;
40
+ /** Host, printed beside the authority in embeds */
41
+ host: string;
42
+ url: string;
43
+ }
44
+ export interface ManualTopic {
45
+ id: ManualTopicId;
46
+ /** Emoji prefix used in the /manual choice list (part of the shipped string) */
47
+ emoji: string;
48
+ /**
49
+ * Per-locale learn-more links. An absent locale means NO link — consumers
50
+ * must render the absent state, never fall back to English.
51
+ */
52
+ links: Partial<Record<LocaleCode, LearnLink>>;
53
+ }
54
+ /** Our own documentation site (Matching Methods target, all locales). */
55
+ export declare const XIVDYETOOLS_DOCS_URL = "https://developers.xivdyetools.app/";
56
+ /** Lodestone by region — Spectrum & Prices resolves region from the user's world. */
57
+ export declare const LODESTONE_BY_REGION: Record<LodestoneRegion, LearnLink>;
58
+ /**
59
+ * The /manual topic roster. `match_image` ships today; the other five need
60
+ * handler + choice registration in the bot (they are part of the 5.0 port).
61
+ */
62
+ export declare const MANUAL_TOPICS: readonly ManualTopic[];
63
+ /**
64
+ * Learn-more link for a topic + locale. Returns null for the absent state —
65
+ * consumers render "no link", never the English URL.
66
+ */
67
+ export declare function getLearnLink(topic: ManualTopicId, locale: LocaleCode): LearnLink | null;
68
+ /** Lodestone link for a game region (Spectrum & Prices topic). */
69
+ export declare function getLodestoneLink(region: LodestoneRegion): LearnLink;
70
+ //# sourceMappingURL=learn-links.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learn-links.d.ts","sourceRoot":"","sources":["../../src/config/learn-links.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,gFAAgF;AAChF,MAAM,MAAM,aAAa,GACrB,aAAa,GACb,cAAc,GACd,UAAU,GACV,kBAAkB,GAClB,iBAAiB,GACjB,gBAAgB,CAAC;AAErB,kEAAkE;AAClE,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE/D,MAAM,WAAW,SAAS;IACxB,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,aAAa,CAAC;IAClB,gFAAgF;IAChF,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;CAC/C;AAID,yEAAyE;AACzE,eAAO,MAAM,oBAAoB,wCAAwC,CAAC;AAE1E,qFAAqF;AACrF,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,eAAe,EAAE,SAAS,CA0BlE,CAAC;AAQF;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,WAAW,EAsF/C,CAAC;AAEF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,IAAI,CAGvF;AAED,kEAAkE;AAClE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAEnE"}