@dicebear/core 10.0.0-rc.1 → 10.0.0-rc.3

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 (59) hide show
  1. package/lib/Avatar.d.ts +17 -1
  2. package/lib/Avatar.js +23 -5
  3. package/lib/Error/CircularColorReferenceError.d.ts +4 -0
  4. package/lib/Error/CircularColorReferenceError.js +4 -0
  5. package/lib/Error/OptionsValidationError.d.ts +3 -0
  6. package/lib/Error/OptionsValidationError.js +3 -0
  7. package/lib/Error/StyleValidationError.d.ts +3 -0
  8. package/lib/Error/StyleValidationError.js +3 -0
  9. package/lib/Error/ValidationError.d.ts +4 -0
  10. package/lib/Error/ValidationError.js +4 -0
  11. package/lib/Options.d.ts +39 -18
  12. package/lib/Options.js +64 -164
  13. package/lib/OptionsDescriptor.d.ts +8 -0
  14. package/lib/OptionsDescriptor.js +14 -6
  15. package/lib/Prng/Fnv1a.d.ts +14 -0
  16. package/lib/Prng/Fnv1a.js +14 -3
  17. package/lib/Prng/Mulberry32.d.ts +22 -0
  18. package/lib/Prng/Mulberry32.js +22 -8
  19. package/lib/Prng.d.ts +35 -0
  20. package/lib/Prng.js +35 -6
  21. package/lib/Renderer.d.ts +11 -2
  22. package/lib/Renderer.js +60 -54
  23. package/lib/Resolver.d.ts +62 -0
  24. package/lib/Resolver.js +203 -0
  25. package/lib/Style/Canvas.d.ts +14 -0
  26. package/lib/Style/Canvas.js +14 -0
  27. package/lib/Style/Color.d.ts +14 -0
  28. package/lib/Style/Color.js +14 -0
  29. package/lib/Style/Component.d.ts +50 -1
  30. package/lib/Style/Component.js +88 -9
  31. package/lib/Style/ComponentTranslate.d.ts +10 -0
  32. package/lib/Style/ComponentTranslate.js +10 -0
  33. package/lib/Style/ComponentVariant.d.ts +10 -0
  34. package/lib/Style/ComponentVariant.js +10 -0
  35. package/lib/Style/Element.d.ts +25 -0
  36. package/lib/Style/Element.js +25 -0
  37. package/lib/Style/Meta.d.ts +16 -0
  38. package/lib/Style/Meta.js +16 -0
  39. package/lib/Style/MetaCreator.d.ts +9 -0
  40. package/lib/Style/MetaCreator.js +9 -0
  41. package/lib/Style/MetaLicense.d.ts +12 -0
  42. package/lib/Style/MetaLicense.js +12 -0
  43. package/lib/Style/MetaSource.d.ts +10 -0
  44. package/lib/Style/MetaSource.js +10 -0
  45. package/lib/Style.d.ts +37 -1
  46. package/lib/Style.js +90 -6
  47. package/lib/StyleDefinition.d.ts +8 -3
  48. package/lib/StyleOptions.d.ts +12 -10
  49. package/lib/Utils/Color.d.ts +28 -0
  50. package/lib/Utils/Color.js +28 -8
  51. package/lib/Utils/Initials.d.ts +10 -0
  52. package/lib/Utils/Initials.js +10 -3
  53. package/lib/Utils/License.d.ts +14 -0
  54. package/lib/Utils/License.js +14 -0
  55. package/lib/Utils/Xml.d.ts +6 -0
  56. package/lib/Utils/Xml.js +6 -0
  57. package/lib/Validator/OptionsValidator.js +1569 -1700
  58. package/lib/Validator/StyleValidator.js +3453 -3197
  59. package/package.json +2 -2
@@ -1,7 +1,29 @@
1
+ /**
2
+ * Mulberry32 PRNG — stateful, matching the C reference by Tommy Ettinger.
3
+ *
4
+ * C original:
5
+ * ```c
6
+ * uint32_t z = (x += 0x6D2B79F5UL);
7
+ * z = (z ^ (z >> 15)) * (z | 1UL);
8
+ * z ^= z + (z ^ (z >> 7)) * (z | 61UL);
9
+ * return z ^ (z >> 14);
10
+ * ```
11
+ *
12
+ * @see https://gist.github.com/tommyettinger/46a874533244883189143505d203312c
13
+ */
1
14
  export declare class Mulberry32 {
2
15
  #private;
3
16
  constructor(seed: number);
17
+ /**
18
+ * Advances the state and returns the next unsigned 32-bit value.
19
+ */
4
20
  next(): number;
21
+ /**
22
+ * Advances the state and returns the next value in `[0, 1)`.
23
+ */
5
24
  nextFloat(): number;
25
+ /**
26
+ * Returns the current internal state, useful for snapshotting.
27
+ */
6
28
  state(): number;
7
29
  }
@@ -10,29 +10,43 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
12
  var _Mulberry32_state;
13
- // Mulberry32 PRNG — stateful, matching the C reference by Tommy Ettinger.
14
- // https://gist.github.com/tommyettinger/46a874533244883189143505d203312c
15
- //
16
- // C original:
17
- // uint32_t z = (x += 0x6D2B79F5UL);
18
- // z = (z ^ (z >> 15)) * (z | 1UL);
19
- // z ^= z + (z ^ (z >> 7)) * (z | 61UL);
20
- // return z ^ (z >> 14);
21
13
  const UINT32_MAX_PLUS_1 = 2 ** 32;
14
+ /**
15
+ * Mulberry32 PRNG — stateful, matching the C reference by Tommy Ettinger.
16
+ *
17
+ * C original:
18
+ * ```c
19
+ * uint32_t z = (x += 0x6D2B79F5UL);
20
+ * z = (z ^ (z >> 15)) * (z | 1UL);
21
+ * z ^= z + (z ^ (z >> 7)) * (z | 61UL);
22
+ * return z ^ (z >> 14);
23
+ * ```
24
+ *
25
+ * @see https://gist.github.com/tommyettinger/46a874533244883189143505d203312c
26
+ */
22
27
  export class Mulberry32 {
23
28
  constructor(seed) {
24
29
  _Mulberry32_state.set(this, void 0);
25
30
  __classPrivateFieldSet(this, _Mulberry32_state, seed, "f");
26
31
  }
32
+ /**
33
+ * Advances the state and returns the next unsigned 32-bit value.
34
+ */
27
35
  next() {
28
36
  const z = (__classPrivateFieldSet(this, _Mulberry32_state, (__classPrivateFieldGet(this, _Mulberry32_state, "f") + 0x6d2b79f5) | 0, "f"));
29
37
  let t = Math.imul(z ^ (z >>> 15), z | 1);
30
38
  t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
31
39
  return ((t ^ (t >>> 14)) >>> 0);
32
40
  }
41
+ /**
42
+ * Advances the state and returns the next value in `[0, 1)`.
43
+ */
33
44
  nextFloat() {
34
45
  return this.next() / UINT32_MAX_PLUS_1;
35
46
  }
47
+ /**
48
+ * Returns the current internal state, useful for snapshotting.
49
+ */
36
50
  state() {
37
51
  return __classPrivateFieldGet(this, _Mulberry32_state, "f");
38
52
  }
package/lib/Prng.d.ts CHANGED
@@ -1,11 +1,46 @@
1
+ /**
2
+ * Key-based pseudorandom number generator.
3
+ *
4
+ * Each method takes a key that, combined with the seed, produces a
5
+ * deterministic value. The same seed + key always yields the same result,
6
+ * regardless of call order.
7
+ */
1
8
  export declare class Prng {
2
9
  #private;
3
10
  constructor(seed: string);
11
+ /**
12
+ * Picks a single item from `items` deterministically. Returns `undefined`
13
+ * for an empty list. Items are sorted by their string representation
14
+ * before picking so that input order does not affect the result.
15
+ */
4
16
  pick<T>(key: string, items: readonly T[]): T | undefined;
17
+ /**
18
+ * Picks an item from `entries` proportional to its weight. When all weights
19
+ * are zero, falls back to an unweighted {@link pick}. Returns `undefined`
20
+ * for an empty list.
21
+ */
5
22
  weightedPick<T>(key: string, entries: readonly (readonly [T, number])[]): T | undefined;
23
+ /**
24
+ * Returns `true` with the given probability (0–100, default 50).
25
+ */
6
26
  bool(key: string, likelihood?: number): boolean;
27
+ /**
28
+ * Returns a deterministic float in the closed range `[min(values), max(values)]`,
29
+ * rounded to four decimal places. Returns `undefined` for an empty list.
30
+ */
7
31
  float(key: string, values: readonly number[]): number | undefined;
32
+ /**
33
+ * Returns a deterministic integer in the closed range
34
+ * `[min(values), max(values)]`. Returns `undefined` for an empty list.
35
+ */
8
36
  integer(key: string, values: readonly number[]): number | undefined;
37
+ /**
38
+ * Fisher-Yates shuffle with chained Mulberry32 state.
39
+ */
9
40
  shuffle<T>(key: string, items: readonly T[]): T[];
41
+ /**
42
+ * Returns a single float in `[0, 1)` derived from `seed:key`. The same
43
+ * seed/key pair always produces the same value.
44
+ */
10
45
  getValue(key: string): number;
11
46
  }
package/lib/Prng.js CHANGED
@@ -12,17 +12,24 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
12
12
  var _Prng_instances, _Prng_seed, _Prng_compareByCodePoint;
13
13
  import { Fnv1a } from './Prng/Fnv1a.js';
14
14
  import { Mulberry32 } from './Prng/Mulberry32.js';
15
- // Key-based pseudorandom number generator.
16
- //
17
- // Each method takes a key that, combined with the seed, produces a
18
- // deterministic value. The same seed + key always yields the same result,
19
- // regardless of call order.
15
+ /**
16
+ * Key-based pseudorandom number generator.
17
+ *
18
+ * Each method takes a key that, combined with the seed, produces a
19
+ * deterministic value. The same seed + key always yields the same result,
20
+ * regardless of call order.
21
+ */
20
22
  export class Prng {
21
23
  constructor(seed) {
22
24
  _Prng_instances.add(this);
23
25
  _Prng_seed.set(this, void 0);
24
26
  __classPrivateFieldSet(this, _Prng_seed, seed, "f");
25
27
  }
28
+ /**
29
+ * Picks a single item from `items` deterministically. Returns `undefined`
30
+ * for an empty list. Items are sorted by their string representation
31
+ * before picking so that input order does not affect the result.
32
+ */
26
33
  pick(key, items) {
27
34
  if (items.length === 0) {
28
35
  return undefined;
@@ -34,6 +41,11 @@ export class Prng {
34
41
  const index = Math.floor(this.getValue(key) * sorted.length);
35
42
  return sorted[index];
36
43
  }
44
+ /**
45
+ * Picks an item from `entries` proportional to its weight. When all weights
46
+ * are zero, falls back to an unweighted {@link pick}. Returns `undefined`
47
+ * for an empty list.
48
+ */
37
49
  weightedPick(key, entries) {
38
50
  if (entries.length === 0) {
39
51
  return undefined;
@@ -53,9 +65,16 @@ export class Prng {
53
65
  }
54
66
  return sorted[sorted.length - 1][0];
55
67
  }
68
+ /**
69
+ * Returns `true` with the given probability (0–100, default 50).
70
+ */
56
71
  bool(key, likelihood = 50) {
57
72
  return this.getValue(key) * 100 < likelihood;
58
73
  }
74
+ /**
75
+ * Returns a deterministic float in the closed range `[min(values), max(values)]`,
76
+ * rounded to four decimal places. Returns `undefined` for an empty list.
77
+ */
59
78
  float(key, values) {
60
79
  if (values.length === 0) {
61
80
  return undefined;
@@ -64,6 +83,10 @@ export class Prng {
64
83
  const max = Math.max(...values);
65
84
  return Math.round((min + this.getValue(key) * (max - min)) * 10000) / 10000;
66
85
  }
86
+ /**
87
+ * Returns a deterministic integer in the closed range
88
+ * `[min(values), max(values)]`. Returns `undefined` for an empty list.
89
+ */
67
90
  integer(key, values) {
68
91
  if (values.length === 0) {
69
92
  return undefined;
@@ -72,7 +95,9 @@ export class Prng {
72
95
  const max = Math.max(...values);
73
96
  return Math.floor(this.getValue(key) * (max - min + 1)) + min;
74
97
  }
75
- // Fisher-Yates shuffle with chained Mulberry32 state.
98
+ /**
99
+ * Fisher-Yates shuffle with chained Mulberry32 state.
100
+ */
76
101
  shuffle(key, items) {
77
102
  const result = Array.from(items).sort(__classPrivateFieldGet(this, _Prng_instances, "m", _Prng_compareByCodePoint));
78
103
  const prng = new Mulberry32(Fnv1a.hash(__classPrivateFieldGet(this, _Prng_seed, "f") + ':' + key));
@@ -84,6 +109,10 @@ export class Prng {
84
109
  }
85
110
  return result;
86
111
  }
112
+ /**
113
+ * Returns a single float in `[0, 1)` derived from `seed:key`. The same
114
+ * seed/key pair always produces the same value.
115
+ */
87
116
  getValue(key) {
88
117
  return new Mulberry32(Fnv1a.hash(__classPrivateFieldGet(this, _Prng_seed, "f") + ':' + key)).nextFloat();
89
118
  }
package/lib/Renderer.d.ts CHANGED
@@ -1,7 +1,16 @@
1
1
  import type { Style } from './Style.js';
2
- import type { Options } from './Options.js';
2
+ import type { Resolver } from './Resolver.js';
3
+ /**
4
+ * Walks a style's element tree and turns it into the final SVG markup.
5
+ *
6
+ * The renderer is single-use: it accumulates `<defs>` entries and per-render
7
+ * caches across method calls, so a fresh instance is required per avatar.
8
+ */
3
9
  export declare class Renderer {
4
10
  #private;
5
- constructor(style: Style, options: Options);
11
+ constructor(style: Style, resolver: Resolver);
12
+ /**
13
+ * Builds the complete SVG document for the avatar.
14
+ */
6
15
  render(): string;
7
16
  }
package/lib/Renderer.js CHANGED
@@ -9,22 +9,31 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _Renderer_instances, _Renderer_style, _Renderer_options, _Renderer_defs, _Renderer_cachedSeedHash, _Renderer_cachedInitials, _Renderer_applyFlip, _Renderer_applyScale, _Renderer_applyBorderRadius, _Renderer_applyRotate, _Renderer_applyTranslate, _Renderer_renderBackground, _Renderer_randomizeIds, _Renderer_renderElements, _Renderer_renderElement, _Renderer_renderSvgElement, _Renderer_renderTextElement, _Renderer_renderComponentElement, _Renderer_buildTransforms, _Renderer_renderAttributes, _Renderer_resolveAttributeValue, _Renderer_resolveColorReference, _Renderer_buildGradientDef, _Renderer_resolveValue, _Renderer_resolveVariable, _Renderer_initials, _Renderer_hashSeed;
12
+ var _Renderer_instances, _Renderer_style, _Renderer_resolver, _Renderer_defs, _Renderer_cachedSeedHash, _Renderer_cachedInitials, _Renderer_applyFlip, _Renderer_applyScale, _Renderer_applyBorderRadius, _Renderer_applyRotate, _Renderer_applyTranslate, _Renderer_renderBackground, _Renderer_randomizeIds, _Renderer_renderElements, _Renderer_renderElement, _Renderer_renderSvgElement, _Renderer_renderTextElement, _Renderer_renderComponentElement, _Renderer_buildTransforms, _Renderer_renderAttributes, _Renderer_resolveAttributeValue, _Renderer_resolveColorReference, _Renderer_buildGradientDef, _Renderer_resolveValue, _Renderer_resolveVariable, _Renderer_initials, _Renderer_hashSeed;
13
13
  import { Fnv1a } from './Prng/Fnv1a.js';
14
14
  import { Initials } from './Utils/Initials.js';
15
15
  import { License } from './Utils/License.js';
16
16
  import { Xml } from './Utils/Xml.js';
17
+ /**
18
+ * Walks a style's element tree and turns it into the final SVG markup.
19
+ *
20
+ * The renderer is single-use: it accumulates `<defs>` entries and per-render
21
+ * caches across method calls, so a fresh instance is required per avatar.
22
+ */
17
23
  export class Renderer {
18
- constructor(style, options) {
24
+ constructor(style, resolver) {
19
25
  _Renderer_instances.add(this);
20
26
  _Renderer_style.set(this, void 0);
21
- _Renderer_options.set(this, void 0);
27
+ _Renderer_resolver.set(this, void 0);
22
28
  _Renderer_defs.set(this, new Map());
23
29
  _Renderer_cachedSeedHash.set(this, void 0);
24
30
  _Renderer_cachedInitials.set(this, void 0);
25
31
  __classPrivateFieldSet(this, _Renderer_style, style, "f");
26
- __classPrivateFieldSet(this, _Renderer_options, options, "f");
32
+ __classPrivateFieldSet(this, _Renderer_resolver, resolver, "f");
27
33
  }
34
+ /**
35
+ * Builds the complete SVG document for the avatar.
36
+ */
28
37
  render() {
29
38
  const canvas = __classPrivateFieldGet(this, _Renderer_style, "f").canvas();
30
39
  const background = __classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_renderBackground).call(this, canvas);
@@ -40,8 +49,8 @@ export class Renderer {
40
49
  const defs = __classPrivateFieldGet(this, _Renderer_defs, "f").size > 0
41
50
  ? `<defs>${Array.from(__classPrivateFieldGet(this, _Renderer_defs, "f").values()).join('')}</defs>`
42
51
  : '';
43
- const size = __classPrivateFieldGet(this, _Renderer_options, "f").size();
44
- const title = __classPrivateFieldGet(this, _Renderer_options, "f").title();
52
+ const size = __classPrivateFieldGet(this, _Renderer_resolver, "f").size();
53
+ const title = __classPrivateFieldGet(this, _Renderer_resolver, "f").title();
45
54
  const escapedTitle = title !== undefined ? Xml.escape(title) : undefined;
46
55
  const attrs = [
47
56
  'xmlns="http://www.w3.org/2000/svg"',
@@ -62,14 +71,14 @@ export class Renderer {
62
71
  }
63
72
  const titleElement = escapedTitle !== undefined ? `<title>${escapedTitle}</title>` : '';
64
73
  let svg = `<svg ${attrs.join(' ')}>${metadata}${defs}${titleElement}${body}</svg>`;
65
- if (__classPrivateFieldGet(this, _Renderer_options, "f").idRandomization()) {
74
+ if (__classPrivateFieldGet(this, _Renderer_resolver, "f").idRandomization()) {
66
75
  svg = __classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_randomizeIds).call(this, svg);
67
76
  }
68
77
  return svg;
69
78
  }
70
79
  }
71
- _Renderer_style = new WeakMap(), _Renderer_options = new WeakMap(), _Renderer_defs = new WeakMap(), _Renderer_cachedSeedHash = new WeakMap(), _Renderer_cachedInitials = new WeakMap(), _Renderer_instances = new WeakSet(), _Renderer_applyFlip = function _Renderer_applyFlip(body, canvas) {
72
- const flip = __classPrivateFieldGet(this, _Renderer_options, "f").flip();
80
+ _Renderer_style = new WeakMap(), _Renderer_resolver = new WeakMap(), _Renderer_defs = new WeakMap(), _Renderer_cachedSeedHash = new WeakMap(), _Renderer_cachedInitials = new WeakMap(), _Renderer_instances = new WeakSet(), _Renderer_applyFlip = function _Renderer_applyFlip(body, canvas) {
81
+ const flip = __classPrivateFieldGet(this, _Renderer_resolver, "f").flip();
73
82
  if (flip === 'none') {
74
83
  return body;
75
84
  }
@@ -89,7 +98,7 @@ _Renderer_style = new WeakMap(), _Renderer_options = new WeakMap(), _Renderer_de
89
98
  }
90
99
  return `<g transform="${transform}">${body}</g>`;
91
100
  }, _Renderer_applyScale = function _Renderer_applyScale(body, canvas) {
92
- const scale = __classPrivateFieldGet(this, _Renderer_options, "f").scale();
101
+ const scale = __classPrivateFieldGet(this, _Renderer_resolver, "f").scale();
93
102
  if (scale === 1) {
94
103
  return body;
95
104
  }
@@ -97,17 +106,14 @@ _Renderer_style = new WeakMap(), _Renderer_options = new WeakMap(), _Renderer_de
97
106
  const cy = canvas.height() / 2;
98
107
  return `<g transform="translate(${cx}, ${cy}) scale(${scale}) translate(${-cx}, ${-cy})">${body}</g>`;
99
108
  }, _Renderer_applyBorderRadius = function _Renderer_applyBorderRadius(body, canvas) {
100
- const radius = __classPrivateFieldGet(this, _Renderer_options, "f").borderRadius();
101
- if (radius === 0) {
102
- return body;
103
- }
109
+ const radius = __classPrivateFieldGet(this, _Renderer_resolver, "f").borderRadius();
104
110
  const id = `clip-${__classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_hashSeed).call(this)}`;
105
111
  const rx = (radius / 100) * canvas.width();
106
112
  const ry = (radius / 100) * canvas.height();
107
113
  __classPrivateFieldGet(this, _Renderer_defs, "f").set(id, `<clipPath id="${id}"><rect width="${canvas.width()}" height="${canvas.height()}" rx="${rx}" ry="${ry}"/></clipPath>`);
108
114
  return `<g clip-path="url(#${id})">${body}</g>`;
109
115
  }, _Renderer_applyRotate = function _Renderer_applyRotate(body, canvas) {
110
- const rotate = __classPrivateFieldGet(this, _Renderer_options, "f").rotate();
116
+ const rotate = __classPrivateFieldGet(this, _Renderer_resolver, "f").rotate();
111
117
  if (rotate === 0) {
112
118
  return body;
113
119
  }
@@ -115,8 +121,8 @@ _Renderer_style = new WeakMap(), _Renderer_options = new WeakMap(), _Renderer_de
115
121
  const cy = canvas.height() / 2;
116
122
  return `<g transform="rotate(${rotate}, ${cx}, ${cy})">${body}</g>`;
117
123
  }, _Renderer_applyTranslate = function _Renderer_applyTranslate(body, canvas) {
118
- const tx = __classPrivateFieldGet(this, _Renderer_options, "f").translateX();
119
- const ty = __classPrivateFieldGet(this, _Renderer_options, "f").translateY();
124
+ const tx = __classPrivateFieldGet(this, _Renderer_resolver, "f").translateX();
125
+ const ty = __classPrivateFieldGet(this, _Renderer_resolver, "f").translateY();
120
126
  if (tx === 0 && ty === 0) {
121
127
  return body;
122
128
  }
@@ -124,15 +130,12 @@ _Renderer_style = new WeakMap(), _Renderer_options = new WeakMap(), _Renderer_de
124
130
  const y = (ty / 100) * canvas.height();
125
131
  return `<g transform="translate(${x}, ${y})">${body}</g>`;
126
132
  }, _Renderer_renderBackground = function _Renderer_renderBackground(canvas) {
127
- const colors = __classPrivateFieldGet(this, _Renderer_options, "f").color('background');
133
+ const colors = __classPrivateFieldGet(this, _Renderer_resolver, "f").color('background');
128
134
  if (colors.length === 0) {
129
135
  return '';
130
136
  }
131
137
  return `<rect width="${canvas.width()}" height="${canvas.height()}" fill="${Xml.escape(__classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_resolveColorReference).call(this, 'background'))}"/>`;
132
138
  }, _Renderer_randomizeIds = function _Renderer_randomizeIds(svg) {
133
- // Uses Math.random() intentionally — a PRNG-based suffix would
134
- // produce the same ID for the same seed, preventing two identical
135
- // avatars from coexisting in the same document.
136
139
  const suffix = Math.floor(Math.random() * 0xffffff)
137
140
  .toString(16)
138
141
  .padStart(6, '0');
@@ -183,15 +186,15 @@ _Renderer_style = new WeakMap(), _Renderer_options = new WeakMap(), _Renderer_de
183
186
  const value = element.value();
184
187
  return value !== undefined ? Xml.escape(__classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_resolveValue).call(this, value)) : '';
185
188
  }, _Renderer_renderComponentElement = function _Renderer_renderComponentElement(element) {
186
- const value = element.value();
187
- if (typeof value !== 'string') {
189
+ const componentName = element.name();
190
+ if (typeof componentName !== 'string') {
188
191
  return '';
189
192
  }
190
- const variantName = __classPrivateFieldGet(this, _Renderer_options, "f").variant(value);
193
+ const variantName = __classPrivateFieldGet(this, _Renderer_resolver, "f").variant(componentName);
191
194
  if (!variantName) {
192
195
  return '';
193
196
  }
194
- const component = __classPrivateFieldGet(this, _Renderer_style, "f").components().get(value);
197
+ const component = __classPrivateFieldGet(this, _Renderer_style, "f").components().get(componentName);
195
198
  if (!component) {
196
199
  return '';
197
200
  }
@@ -199,29 +202,33 @@ _Renderer_style = new WeakMap(), _Renderer_options = new WeakMap(), _Renderer_de
199
202
  if (!variant) {
200
203
  return '';
201
204
  }
202
- const body = __classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_renderElements).call(this, variant.elements());
203
- const transforms = __classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_buildTransforms).call(this, value);
204
- if (transforms.length === 0) {
205
- return body;
205
+ const id = `${component.sourceName()}-${variantName}-${__classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_hashSeed).call(this)}`;
206
+ if (!__classPrivateFieldGet(this, _Renderer_defs, "f").has(id)) {
207
+ const body = __classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_renderElements).call(this, variant.elements());
208
+ __classPrivateFieldGet(this, _Renderer_defs, "f").set(id, `<g id="${id}">${body}</g>`);
209
+ }
210
+ const transforms = __classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_buildTransforms).call(this, component);
211
+ const transformAttr = transforms.length > 0 ? ` transform="${transforms.join(' ')}"` : '';
212
+ return `<use${transformAttr} href="#${id}"/>`;
213
+ }, _Renderer_buildTransforms = function _Renderer_buildTransforms(component) {
214
+ const { rotate, translateX, translateY, scale } = __classPrivateFieldGet(this, _Renderer_resolver, "f").componentTransform(component.name());
215
+ if (translateX === 0 && translateY === 0 && rotate === 0 && scale === 1) {
216
+ return [];
206
217
  }
207
- return `<g transform="${transforms.join(' ')}">${body}</g>`;
208
- }, _Renderer_buildTransforms = function _Renderer_buildTransforms(componentName) {
209
218
  const transforms = [];
210
- const translateX = __classPrivateFieldGet(this, _Renderer_options, "f").translateX(componentName);
211
- const translateY = __classPrivateFieldGet(this, _Renderer_options, "f").translateY(componentName);
212
- const rotate = __classPrivateFieldGet(this, _Renderer_options, "f").rotate(componentName);
219
+ const cx = component.width() / 2;
220
+ const cy = component.height() / 2;
213
221
  if (translateX !== 0 || translateY !== 0) {
214
- transforms.push(`translate(${translateX}, ${translateY})`);
222
+ const x = Math.round((translateX / 100) * component.width() * 10000) / 10000;
223
+ const y = Math.round((translateY / 100) * component.height() * 10000) / 10000;
224
+ transforms.push(`translate(${x}, ${y})`);
215
225
  }
216
226
  if (rotate !== 0) {
217
- const component = __classPrivateFieldGet(this, _Renderer_style, "f").components().get(componentName);
218
- if (!component) {
219
- return transforms;
220
- }
221
- const cx = component.width() / 2;
222
- const cy = component.height() / 2;
223
227
  transforms.push(`rotate(${rotate}, ${cx}, ${cy})`);
224
228
  }
229
+ if (scale !== 1) {
230
+ transforms.push(`translate(${cx}, ${cy}) scale(${scale}) translate(${-cx}, ${-cy})`);
231
+ }
225
232
  return transforms;
226
233
  }, _Renderer_renderAttributes = function _Renderer_renderAttributes(attributes) {
227
234
  if (!attributes) {
@@ -243,19 +250,18 @@ _Renderer_style = new WeakMap(), _Renderer_options = new WeakMap(), _Renderer_de
243
250
  return value;
244
251
  }
245
252
  if (value.type === 'color') {
246
- return __classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_resolveColorReference).call(this, value.value);
253
+ return __classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_resolveColorReference).call(this, value.name);
247
254
  }
248
- return __classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_resolveVariable).call(this, value.value);
255
+ return __classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_resolveVariable).call(this, value.name);
249
256
  }, _Renderer_resolveColorReference = function _Renderer_resolveColorReference(name) {
250
- const colors = __classPrivateFieldGet(this, _Renderer_options, "f").color(name);
251
- const fill = __classPrivateFieldGet(this, _Renderer_options, "f").colorFill(name);
257
+ const colors = __classPrivateFieldGet(this, _Renderer_resolver, "f").color(name);
258
+ const fill = __classPrivateFieldGet(this, _Renderer_resolver, "f").colorFill(name);
252
259
  if (fill === 'solid' || colors.length <= 1) {
253
260
  return colors[0] ?? 'none';
254
261
  }
255
- return __classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_buildGradientDef).call(this, name, colors);
256
- }, _Renderer_buildGradientDef = function _Renderer_buildGradientDef(name, colors) {
257
- const fill = __classPrivateFieldGet(this, _Renderer_options, "f").colorFill(name);
258
- const rotation = __classPrivateFieldGet(this, _Renderer_options, "f").colorAngle(name);
262
+ return __classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_buildGradientDef).call(this, name, colors, fill);
263
+ }, _Renderer_buildGradientDef = function _Renderer_buildGradientDef(name, colors, fill) {
264
+ const rotation = __classPrivateFieldGet(this, _Renderer_resolver, "f").colorAngle(name);
259
265
  const id = `${name}-color-${__classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_hashSeed).call(this)}`;
260
266
  const tag = fill === 'linear' ? 'linearGradient' : 'radialGradient';
261
267
  const rotateAttr = rotation !== 0
@@ -272,7 +278,7 @@ _Renderer_style = new WeakMap(), _Renderer_options = new WeakMap(), _Renderer_de
272
278
  return value;
273
279
  }
274
280
  if (value.type === 'variable') {
275
- return __classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_resolveVariable).call(this, value.value);
281
+ return __classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_resolveVariable).call(this, value.name);
276
282
  }
277
283
  return '';
278
284
  }, _Renderer_resolveVariable = function _Renderer_resolveVariable(name) {
@@ -282,12 +288,12 @@ _Renderer_style = new WeakMap(), _Renderer_options = new WeakMap(), _Renderer_de
282
288
  case 'initials':
283
289
  return __classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_initials).call(this);
284
290
  case 'fontWeight':
285
- return String(__classPrivateFieldGet(this, _Renderer_options, "f").fontWeight());
291
+ return String(__classPrivateFieldGet(this, _Renderer_resolver, "f").fontWeight());
286
292
  case 'fontFamily':
287
- return __classPrivateFieldGet(this, _Renderer_options, "f").fontFamily();
293
+ return __classPrivateFieldGet(this, _Renderer_resolver, "f").fontFamily();
288
294
  }
289
295
  }, _Renderer_initials = function _Renderer_initials() {
290
- return (__classPrivateFieldSet(this, _Renderer_cachedInitials, __classPrivateFieldGet(this, _Renderer_cachedInitials, "f") ?? Initials.fromSeed(__classPrivateFieldGet(this, _Renderer_options, "f").seed()), "f"));
296
+ return (__classPrivateFieldSet(this, _Renderer_cachedInitials, __classPrivateFieldGet(this, _Renderer_cachedInitials, "f") ?? Initials.fromSeed(__classPrivateFieldGet(this, _Renderer_resolver, "f").seed()), "f"));
291
297
  }, _Renderer_hashSeed = function _Renderer_hashSeed() {
292
- return (__classPrivateFieldSet(this, _Renderer_cachedSeedHash, __classPrivateFieldGet(this, _Renderer_cachedSeedHash, "f") ?? Fnv1a.hex(__classPrivateFieldGet(this, _Renderer_options, "f").seed()), "f"));
298
+ return (__classPrivateFieldSet(this, _Renderer_cachedSeedHash, __classPrivateFieldGet(this, _Renderer_cachedSeedHash, "f") ?? Fnv1a.hex(__classPrivateFieldGet(this, _Renderer_resolver, "f").seed()), "f"));
293
299
  };
@@ -0,0 +1,62 @@
1
+ import { Options } from './Options.js';
2
+ import type { Style } from './Style.js';
3
+ import type { StyleOptionsFlipValue, StyleOptionsColorFillValue, StyleOptions } from './StyleOptions.js';
4
+ /**
5
+ * Bundles the three inputs needed to derive any deterministic value for an
6
+ * avatar — the {@link Style}, the validated user {@link Options}, and a
7
+ * seeded {@link Prng} — and exposes them as named accessors. Each accessor
8
+ * memoizes its result so that repeated calls cannot drift, and the memo
9
+ * doubles as the snapshot returned by {@link resolved}.
10
+ */
11
+ export declare class Resolver<D = unknown> {
12
+ #private;
13
+ constructor(style: Style<D>, options: Options<D>);
14
+ seed(): string;
15
+ size(): number | undefined;
16
+ idRandomization(): boolean;
17
+ title(): string | undefined;
18
+ flip(): StyleOptionsFlipValue;
19
+ fontFamily(): string;
20
+ fontWeight(): number;
21
+ scale(): number;
22
+ borderRadius(): number;
23
+ rotate(): number;
24
+ translateX(): number;
25
+ translateY(): number;
26
+ /**
27
+ * Selects a variant for the given component. Depending on what was passed
28
+ * as `${name}Variant` in the input data:
29
+ *
30
+ * - `undefined`: PRNG picks from all style variants using their weights.
31
+ * - `string` or `string[]`: PRNG picks from the given subset (weight 1 each).
32
+ * - `Record<string, number>`: PRNG picks using the provided weights.
33
+ *
34
+ * Only variants that exist in the style definition are considered.
35
+ */
36
+ variant(name: string): string | undefined;
37
+ color(name: string): readonly string[];
38
+ colorFill(name: string): StyleOptionsColorFillValue;
39
+ colorAngle(name: string): number;
40
+ /**
41
+ * Per-component transform values are render-time decorations derived per
42
+ * `<use>` reference, not user-input options that should round-trip. They
43
+ * are intentionally not memoized and so never appear in {@link resolved}.
44
+ */
45
+ componentTransform(name: string): {
46
+ rotate: number;
47
+ translateX: number;
48
+ translateY: number;
49
+ scale: number;
50
+ };
51
+ /**
52
+ * Returns every value that has been touched during this resolution. Only
53
+ * memoized entries are included; unset options remain `undefined` and
54
+ * disappear on `JSON.stringify()`. Per-component transform values from
55
+ * {@link componentTransform} are intentionally not memoized and therefore
56
+ * do not appear in the snapshot.
57
+ *
58
+ * The returned object aliases the internal cache; callers that need
59
+ * isolation (e.g. {@link Avatar.toJSON}) clone it themselves.
60
+ */
61
+ resolved(): StyleOptions<D>;
62
+ }