@dicebear/core 10.0.1 → 10.0.2

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/lib/Options.js CHANGED
@@ -123,5 +123,8 @@ _Options_data = new WeakMap(), _Options_instances = new WeakSet(), _Options_dyna
123
123
  if (typeof value === 'number') {
124
124
  return { min: value, max: value };
125
125
  }
126
- return { min: value[0], max: value[1] };
126
+ if (value.length === 0) {
127
+ return undefined;
128
+ }
129
+ return { min: Math.min(...value), max: Math.max(...value) };
127
130
  };
package/lib/Renderer.js CHANGED
@@ -13,6 +13,7 @@ var _Renderer_instances, _Renderer_style, _Renderer_resolver, _Renderer_defs, _R
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
+ import { Number } from './Utils/Number.js';
16
17
  import { Xml } from './Utils/Xml.js';
17
18
  /**
18
19
  * Walks a style's element tree and turns it into the final SVG markup.
@@ -54,7 +55,7 @@ export class Renderer {
54
55
  const escapedTitle = title !== undefined ? Xml.escape(title) : undefined;
55
56
  const attrs = [
56
57
  'xmlns="http://www.w3.org/2000/svg"',
57
- `viewBox="0 0 ${canvas.width()} ${canvas.height()}"`,
58
+ `viewBox="0 0 ${Number.format(canvas.width())} ${Number.format(canvas.height())}"`,
58
59
  ];
59
60
  const rootAttributes = __classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_renderAttributes).call(this, __classPrivateFieldGet(this, _Renderer_style, "f").attributes());
60
61
  if (rootAttributes) {
@@ -67,7 +68,8 @@ export class Renderer {
67
68
  attrs.push('aria-hidden="true"');
68
69
  }
69
70
  if (size !== undefined) {
70
- attrs.push(`width="${size}"`, `height="${size}"`);
71
+ const sizeValue = Number.format(size);
72
+ attrs.push(`width="${sizeValue}"`, `height="${sizeValue}"`);
71
73
  }
72
74
  const titleElement = escapedTitle !== undefined ? `<title>${escapedTitle}</title>` : '';
73
75
  let svg = `<svg ${attrs.join(' ')}>${metadata}${defs}${titleElement}${body}</svg>`;
@@ -82,8 +84,8 @@ _Renderer_style = new WeakMap(), _Renderer_resolver = new WeakMap(), _Renderer_d
82
84
  if (flip === 'none') {
83
85
  return body;
84
86
  }
85
- const w = canvas.width();
86
- const h = canvas.height();
87
+ const w = Number.format(canvas.width());
88
+ const h = Number.format(canvas.height());
87
89
  let transform;
88
90
  switch (flip) {
89
91
  case 'horizontal':
@@ -104,13 +106,13 @@ _Renderer_style = new WeakMap(), _Renderer_resolver = new WeakMap(), _Renderer_d
104
106
  }
105
107
  const cx = canvas.width() / 2;
106
108
  const cy = canvas.height() / 2;
107
- return `<g transform="translate(${cx}, ${cy}) scale(${scale}) translate(${-cx}, ${-cy})">${body}</g>`;
109
+ return `<g transform="translate(${Number.format(cx)}, ${Number.format(cy)}) scale(${Number.format(scale)}) translate(${Number.format(-cx)}, ${Number.format(-cy)})">${body}</g>`;
108
110
  }, _Renderer_applyBorderRadius = function _Renderer_applyBorderRadius(body, canvas) {
109
111
  const radius = __classPrivateFieldGet(this, _Renderer_resolver, "f").borderRadius();
110
112
  const id = `clip-${__classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_hashSeed).call(this)}`;
111
- const rx = (radius / 100) * canvas.width();
112
- const ry = (radius / 100) * canvas.height();
113
- __classPrivateFieldGet(this, _Renderer_defs, "f").set(id, `<clipPath id="${id}"><rect width="${canvas.width()}" height="${canvas.height()}" rx="${rx}" ry="${ry}"/></clipPath>`);
113
+ const rx = Number.format((radius / 100) * canvas.width());
114
+ const ry = Number.format((radius / 100) * canvas.height());
115
+ __classPrivateFieldGet(this, _Renderer_defs, "f").set(id, `<clipPath id="${id}"><rect width="${Number.format(canvas.width())}" height="${Number.format(canvas.height())}" rx="${rx}" ry="${ry}"/></clipPath>`);
114
116
  return `<g clip-path="url(#${id})">${body}</g>`;
115
117
  }, _Renderer_applyRotate = function _Renderer_applyRotate(body, canvas) {
116
118
  const rotate = __classPrivateFieldGet(this, _Renderer_resolver, "f").rotate();
@@ -119,22 +121,22 @@ _Renderer_style = new WeakMap(), _Renderer_resolver = new WeakMap(), _Renderer_d
119
121
  }
120
122
  const cx = canvas.width() / 2;
121
123
  const cy = canvas.height() / 2;
122
- return `<g transform="rotate(${rotate}, ${cx}, ${cy})">${body}</g>`;
124
+ return `<g transform="rotate(${Number.format(rotate)}, ${Number.format(cx)}, ${Number.format(cy)})">${body}</g>`;
123
125
  }, _Renderer_applyTranslate = function _Renderer_applyTranslate(body, canvas) {
124
126
  const tx = __classPrivateFieldGet(this, _Renderer_resolver, "f").translateX();
125
127
  const ty = __classPrivateFieldGet(this, _Renderer_resolver, "f").translateY();
126
128
  if (tx === 0 && ty === 0) {
127
129
  return body;
128
130
  }
129
- const x = (tx / 100) * canvas.width();
130
- const y = (ty / 100) * canvas.height();
131
+ const x = Number.format((tx / 100) * canvas.width());
132
+ const y = Number.format((ty / 100) * canvas.height());
131
133
  return `<g transform="translate(${x}, ${y})">${body}</g>`;
132
134
  }, _Renderer_renderBackground = function _Renderer_renderBackground(canvas) {
133
135
  const colors = __classPrivateFieldGet(this, _Renderer_resolver, "f").color('background');
134
136
  if (colors.length === 0) {
135
137
  return '';
136
138
  }
137
- return `<rect width="${canvas.width()}" height="${canvas.height()}" fill="${Xml.escape(__classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_resolveColorReference).call(this, 'background'))}"/>`;
139
+ return `<rect width="${Number.format(canvas.width())}" height="${Number.format(canvas.height())}" fill="${Xml.escape(__classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_resolveColorReference).call(this, 'background'))}"/>`;
138
140
  }, _Renderer_randomizeIds = function _Renderer_randomizeIds(svg) {
139
141
  const suffix = Math.floor(Math.random() * 0xffffff)
140
142
  .toString(16)
@@ -227,16 +229,18 @@ _Renderer_style = new WeakMap(), _Renderer_resolver = new WeakMap(), _Renderer_d
227
229
  const transforms = [];
228
230
  const cx = component.width() / 2;
229
231
  const cy = component.height() / 2;
232
+ const cxValue = Number.format(cx);
233
+ const cyValue = Number.format(cy);
230
234
  if (translateX !== 0 || translateY !== 0) {
231
- const x = Math.round((translateX / 100) * component.width() * 10000) / 10000;
232
- const y = Math.round((translateY / 100) * component.height() * 10000) / 10000;
235
+ const x = Number.format((translateX / 100) * component.width());
236
+ const y = Number.format((translateY / 100) * component.height());
233
237
  transforms.push(`translate(${x}, ${y})`);
234
238
  }
235
239
  if (rotate !== 0) {
236
- transforms.push(`rotate(${rotate}, ${cx}, ${cy})`);
240
+ transforms.push(`rotate(${Number.format(rotate)}, ${cxValue}, ${cyValue})`);
237
241
  }
238
242
  if (scale !== 1) {
239
- transforms.push(`translate(${cx}, ${cy}) scale(${scale}) translate(${-cx}, ${-cy})`);
243
+ transforms.push(`translate(${cxValue}, ${cyValue}) scale(${Number.format(scale)}) translate(${Number.format(-cx)}, ${Number.format(-cy)})`);
240
244
  }
241
245
  return transforms;
242
246
  }, _Renderer_renderAttributes = function _Renderer_renderAttributes(attributes) {
@@ -274,10 +278,10 @@ _Renderer_style = new WeakMap(), _Renderer_resolver = new WeakMap(), _Renderer_d
274
278
  const id = `${name}-color-${__classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_hashSeed).call(this)}`;
275
279
  const tag = fill === 'linear' ? 'linearGradient' : 'radialGradient';
276
280
  const rotateAttr = rotation !== 0
277
- ? ` gradientTransform="rotate(${rotation}, 0.5, 0.5)"`
281
+ ? ` gradientTransform="rotate(${Number.format(rotation)}, 0.5, 0.5)"`
278
282
  : '';
279
283
  const stops = colors.map((color, i) => {
280
- const offset = Math.round((i / (colors.length - 1)) * 100);
284
+ const offset = Number.format((i / (colors.length - 1)) * 100);
281
285
  return `<stop offset="${offset}%" stop-color="${Xml.escape(color)}"/>`;
282
286
  });
283
287
  __classPrivateFieldGet(this, _Renderer_defs, "f").set(id, `<${tag} id="${id}"${rotateAttr}>${stops.join('')}</${tag}>`);
@@ -297,7 +301,7 @@ _Renderer_style = new WeakMap(), _Renderer_resolver = new WeakMap(), _Renderer_d
297
301
  case 'initials':
298
302
  return __classPrivateFieldGet(this, _Renderer_instances, "m", _Renderer_initials).call(this);
299
303
  case 'fontWeight':
300
- return String(__classPrivateFieldGet(this, _Renderer_resolver, "f").fontWeight());
304
+ return Number.format(__classPrivateFieldGet(this, _Renderer_resolver, "f").fontWeight());
301
305
  case 'fontFamily':
302
306
  return __classPrivateFieldGet(this, _Renderer_resolver, "f").fontFamily();
303
307
  }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Formats a number for SVG output, rounded to at most 5 decimal places.
3
+ *
4
+ * Rounding to a fixed precision keeps the output bounded and identical across
5
+ * the JS, PHP, and Python ports: every value becomes a multiple of 1e-5 in the
6
+ * SVG coordinate range, which has no exponential form, so the result is built
7
+ * from integer arithmetic (no locale- or language-specific float stringifying).
8
+ * Five decimals is far below sub-pixel precision for any realistic canvas.
9
+ */
10
+ export declare class Number {
11
+ static format(value: number): string;
12
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Formats a number for SVG output, rounded to at most 5 decimal places.
3
+ *
4
+ * Rounding to a fixed precision keeps the output bounded and identical across
5
+ * the JS, PHP, and Python ports: every value becomes a multiple of 1e-5 in the
6
+ * SVG coordinate range, which has no exponential form, so the result is built
7
+ * from integer arithmetic (no locale- or language-specific float stringifying).
8
+ * Five decimals is far below sub-pixel precision for any realistic canvas.
9
+ */
10
+ export class Number {
11
+ static format(value) {
12
+ // `value !== value` and the Infinity literals avoid referencing the global
13
+ // `Number`, which this class shadows within the module.
14
+ if (value !== value) {
15
+ return 'NaN';
16
+ }
17
+ if (value === Infinity) {
18
+ return 'Infinity';
19
+ }
20
+ if (value === -Infinity) {
21
+ return '-Infinity';
22
+ }
23
+ let scaled = Math.round(value * 100000);
24
+ const sign = scaled < 0 ? '-' : '';
25
+ scaled = Math.abs(scaled);
26
+ const integerPart = Math.floor(scaled / 100000);
27
+ const fraction = String(scaled % 100000)
28
+ .padStart(5, '0')
29
+ .replace(/0+$/, '');
30
+ return `${sign}${integerPart}${fraction ? `.${fraction}` : ''}`;
31
+ }
32
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dicebear/core",
3
- "version": "10.0.1",
3
+ "version": "10.0.2",
4
4
  "description": "Unique avatars from dozens of styles — deterministic, customizable, vector-based.",
5
5
  "keywords": [
6
6
  "avatar",