@ewanc26/noise-avatar 0.1.0 → 0.2.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @ewanc26/noise-avatar
2
2
 
3
- Deterministic value-noise avatar generation from a string seed. Zero runtime dependencies, works in any environment with a Canvas API (browsers, jsdom).
3
+ Deterministic value-noise avatar generation from a string seed. Thin opinionated wrapper around [`@ewanc26/noise`](../noise). Zero extra runtime dependencies, works in any environment with a Canvas API (browsers, jsdom).
4
4
 
5
5
  Part of the [`@ewanc26/pkgs`](https://github.com/ewanc26/pkgs) monorepo.
6
6
 
@@ -36,7 +36,7 @@ renderNoiseAvatar(canvas, 'Alice|Subscription');
36
36
 
37
37
  ### `renderNoiseAvatar(canvas, seed, options?)`
38
38
 
39
- Renders a deterministic value-noise texture onto `canvas`. Resizes the canvas to `options.displaySize` (default `64`).
39
+ Renders a deterministic HSL value-noise texture onto `canvas` at `displaySize × displaySize` pixels.
40
40
 
41
41
  | Option | Type | Default | Description |
42
42
  |---|---|---|---|
@@ -48,19 +48,15 @@ Renders a deterministic value-noise texture onto `canvas`. Resizes the canvas to
48
48
 
49
49
  ### `noiseAvatarAction(canvas, seed, options?)`
50
50
 
51
- Svelte action wrapper around `renderNoiseAvatar`. Re-renders when `seed` changes via `update`.
51
+ Svelte action wrapper. Re-renders when `seed` changes via `update`.
52
52
 
53
- ### `hash32(str)`
53
+ ### Re-exported primitives
54
54
 
55
- djb2 hash returns an unsigned 32-bit integer. Exported for custom seed construction.
55
+ `hash32`, `makePrng`, `hslToRgb`, `makeValueNoiseSampler`, and `generateNoisePixels`
56
+ are all re-exported from `@ewanc26/noise` for convenience.
56
57
 
57
- ### `makePrng(seed)`
58
-
59
- Seeded LCG PRNG — returns a `() => number` producing floats in `[0, 1)`.
60
-
61
- ### `hslToRgb(h, s, l)`
62
-
63
- Converts HSL (components in `[0, 1]`) to an RGB triple (`[0, 255]` each).
58
+ For full control over dimensions, FBM octaves, and colour modes, use
59
+ [`@ewanc26/noise`](../noise) directly.
64
60
 
65
61
  ## Licence
66
62
 
package/dist/index.cjs CHANGED
@@ -20,90 +20,49 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- hash32: () => hash32,
24
- hslToRgb: () => hslToRgb,
25
- makePrng: () => makePrng,
23
+ generateNoisePixels: () => import_noise.generateNoisePixels,
24
+ hash32: () => import_noise.hash32,
25
+ hslToRgb: () => import_noise.hslToRgb,
26
+ makePrng: () => import_noise.makePrng,
27
+ makeValueNoiseSampler: () => import_noise.makeValueNoiseSampler,
26
28
  noiseAvatarAction: () => noiseAvatarAction,
27
29
  renderNoiseAvatar: () => renderNoiseAvatar
28
30
  });
29
31
  module.exports = __toCommonJS(index_exports);
30
- function hash32(str) {
31
- let h = 5381;
32
- for (let i = 0; i < str.length; i++) h = Math.imul(33, h) ^ str.charCodeAt(i);
33
- return h >>> 0;
34
- }
35
- function makePrng(seed) {
36
- let s = seed >>> 0;
37
- return () => {
38
- s = Math.imul(1664525, s) + 1013904223 >>> 0;
39
- return s / 4294967296;
32
+ var import_noise = require("@ewanc26/noise");
33
+ var import_noise2 = require("@ewanc26/noise");
34
+ function toRenderOptions(opts) {
35
+ const colorMode = {
36
+ type: "hsl",
37
+ hueRange: opts.hueRange,
38
+ saturationRange: opts.saturationRange,
39
+ lightnessRange: opts.lightnessRange
40
40
  };
41
- }
42
- function hslToRgb(h, s, l) {
43
- const a = s * Math.min(l, 1 - l);
44
- const f = (n) => {
45
- const k = (n + h * 12) % 12;
46
- return l - a * Math.max(-1, Math.min(k - 3, 9 - k, 1));
41
+ return {
42
+ size: opts.displaySize ?? 64,
43
+ gridSize: opts.gridSize,
44
+ colorMode
47
45
  };
48
- return [Math.round(f(0) * 255), Math.round(f(8) * 255), Math.round(f(4) * 255)];
49
- }
50
- function smoothstep(t) {
51
- return t * t * (3 - 2 * t);
52
46
  }
53
47
  function renderNoiseAvatar(canvas, seed, options = {}) {
54
- const {
55
- gridSize = 5,
56
- displaySize = 64,
57
- hueRange = 60,
58
- saturationRange = [45, 70],
59
- lightnessRange = [40, 70]
60
- } = options;
61
- canvas.width = displaySize;
62
- canvas.height = displaySize;
63
- const ctx = canvas.getContext("2d");
64
- if (!ctx) return;
65
- const seedNum = hash32(seed);
66
- const rng = makePrng(seedNum);
67
- const baseHue = seedNum % 360;
68
- const G = gridSize + 1;
69
- const grid = Array.from({ length: G * G }, () => rng());
70
- const gridVal = (gx, gy) => grid[gy * G + gx];
71
- const imageData = ctx.createImageData(displaySize, displaySize);
72
- for (let py = 0; py < displaySize; py++) {
73
- for (let px = 0; px < displaySize; px++) {
74
- const fx = px / displaySize * gridSize;
75
- const fy = py / displaySize * gridSize;
76
- const gx = Math.floor(fx);
77
- const gy = Math.floor(fy);
78
- const tx = smoothstep(fx - gx);
79
- const ty = smoothstep(fy - gy);
80
- const v = (1 - ty) * ((1 - tx) * gridVal(gx, gy) + tx * gridVal(gx + 1, gy)) + ty * ((1 - tx) * gridVal(gx, gy + 1) + tx * gridVal(gx + 1, gy + 1));
81
- const hue = (baseHue + v * hueRange) % 360;
82
- const sat = saturationRange[0] + v * (saturationRange[1] - saturationRange[0]);
83
- const light = lightnessRange[0] + v * (lightnessRange[1] - lightnessRange[0]);
84
- const [r, g, b] = hslToRgb(hue / 360, sat / 100, light / 100);
85
- const i = (py * displaySize + px) * 4;
86
- imageData.data[i] = r;
87
- imageData.data[i + 1] = g;
88
- imageData.data[i + 2] = b;
89
- imageData.data[i + 3] = 255;
90
- }
91
- }
92
- ctx.putImageData(imageData, 0, 0);
48
+ (0, import_noise2.renderNoise)(canvas, seed, toRenderOptions(options));
93
49
  }
94
- function noiseAvatarAction(canvas, seed, options) {
95
- renderNoiseAvatar(canvas, seed, options);
50
+ function noiseAvatarAction(canvas, seed, options = {}) {
51
+ const params = { seed, ...toRenderOptions(options) };
52
+ const action = (0, import_noise2.noiseAction)(canvas, params);
96
53
  return {
97
54
  update(newSeed) {
98
- renderNoiseAvatar(canvas, newSeed, options);
55
+ action.update({ seed: newSeed, ...toRenderOptions(options) });
99
56
  }
100
57
  };
101
58
  }
102
59
  // Annotate the CommonJS export names for ESM import in node:
103
60
  0 && (module.exports = {
61
+ generateNoisePixels,
104
62
  hash32,
105
63
  hslToRgb,
106
64
  makePrng,
65
+ makeValueNoiseSampler,
107
66
  noiseAvatarAction,
108
67
  renderNoiseAvatar
109
68
  });
package/dist/index.d.cts CHANGED
@@ -1,31 +1,18 @@
1
+ export { generateNoisePixels, hash32, hslToRgb, makePrng, makeValueNoiseSampler } from '@ewanc26/noise';
2
+
1
3
  /**
2
4
  * @ewanc26/noise-avatar
3
5
  *
4
- * Deterministic value-noise avatar generation.
6
+ * Opinionated avatar-flavoured wrapper around @ewanc26/noise.
5
7
  *
6
- * Renders a unique, colour-rich noise texture onto an HTMLCanvasElement
7
- * from an arbitrary string seed. The same seed always produces the same image.
8
- * Zero runtime dependencies; works in any environment with a Canvas API.
9
- */
10
- /**
11
- * djb2 hash — returns an unsigned 32-bit integer for any string.
12
- */
13
- declare function hash32(str: string): number;
14
- /**
15
- * Seeded LCG pseudo-random number generator.
16
- * Returns a function that produces floats in [0, 1).
17
- */
18
- declare function makePrng(seed: number): () => number;
19
- /**
20
- * Convert HSL (each component in [0, 1]) to an RGB triple ([0, 255] each).
21
- */
22
- declare function hslToRgb(h: number, s: number, l: number): [number, number, number];
23
- /**
24
- * Options for `renderNoiseAvatar`.
8
+ * Provides a fixed HSL colour mode and square-canvas defaults so callers
9
+ * don't have to think about noise options for the common avatar use-case.
10
+ * The underlying primitives are re-exported for consumers that want them.
25
11
  */
12
+
26
13
  interface NoiseAvatarOptions {
27
14
  /**
28
- * Side length of the internal noise grid (higher = more detail).
15
+ * Side length of the noise grid.
29
16
  * @default 5
30
17
  */
31
18
  gridSize?: number;
@@ -35,7 +22,7 @@ interface NoiseAvatarOptions {
35
22
  */
36
23
  displaySize?: number;
37
24
  /**
38
- * Hue spread (degrees) around the seed-derived base hue.
25
+ * Hue spread in degrees around the seed-derived base hue.
39
26
  * @default 60
40
27
  */
41
28
  hueRange?: number;
@@ -55,11 +42,12 @@ interface NoiseAvatarOptions {
55
42
  *
56
43
  * @param canvas Target HTMLCanvasElement (will be resized to `displaySize`).
57
44
  * @param seed Arbitrary string — same seed always produces the same image.
58
- * @param options Rendering options.
45
+ * @param options Avatar rendering options.
59
46
  */
60
47
  declare function renderNoiseAvatar(canvas: HTMLCanvasElement, seed: string, options?: NoiseAvatarOptions): void;
61
48
  /**
62
- * Create a Svelte action that renders a noise avatar and updates reactively.
49
+ * Svelte action that renders a noise avatar and updates reactively when
50
+ * `seed` changes.
63
51
  *
64
52
  * @example
65
53
  * ```svelte
@@ -70,4 +58,4 @@ declare function noiseAvatarAction(canvas: HTMLCanvasElement, seed: string, opti
70
58
  update(newSeed: string): void;
71
59
  };
72
60
 
73
- export { type NoiseAvatarOptions, hash32, hslToRgb, makePrng, noiseAvatarAction, renderNoiseAvatar };
61
+ export { type NoiseAvatarOptions, noiseAvatarAction, renderNoiseAvatar };
package/dist/index.d.ts CHANGED
@@ -1,31 +1,18 @@
1
+ export { generateNoisePixels, hash32, hslToRgb, makePrng, makeValueNoiseSampler } from '@ewanc26/noise';
2
+
1
3
  /**
2
4
  * @ewanc26/noise-avatar
3
5
  *
4
- * Deterministic value-noise avatar generation.
6
+ * Opinionated avatar-flavoured wrapper around @ewanc26/noise.
5
7
  *
6
- * Renders a unique, colour-rich noise texture onto an HTMLCanvasElement
7
- * from an arbitrary string seed. The same seed always produces the same image.
8
- * Zero runtime dependencies; works in any environment with a Canvas API.
9
- */
10
- /**
11
- * djb2 hash — returns an unsigned 32-bit integer for any string.
12
- */
13
- declare function hash32(str: string): number;
14
- /**
15
- * Seeded LCG pseudo-random number generator.
16
- * Returns a function that produces floats in [0, 1).
17
- */
18
- declare function makePrng(seed: number): () => number;
19
- /**
20
- * Convert HSL (each component in [0, 1]) to an RGB triple ([0, 255] each).
21
- */
22
- declare function hslToRgb(h: number, s: number, l: number): [number, number, number];
23
- /**
24
- * Options for `renderNoiseAvatar`.
8
+ * Provides a fixed HSL colour mode and square-canvas defaults so callers
9
+ * don't have to think about noise options for the common avatar use-case.
10
+ * The underlying primitives are re-exported for consumers that want them.
25
11
  */
12
+
26
13
  interface NoiseAvatarOptions {
27
14
  /**
28
- * Side length of the internal noise grid (higher = more detail).
15
+ * Side length of the noise grid.
29
16
  * @default 5
30
17
  */
31
18
  gridSize?: number;
@@ -35,7 +22,7 @@ interface NoiseAvatarOptions {
35
22
  */
36
23
  displaySize?: number;
37
24
  /**
38
- * Hue spread (degrees) around the seed-derived base hue.
25
+ * Hue spread in degrees around the seed-derived base hue.
39
26
  * @default 60
40
27
  */
41
28
  hueRange?: number;
@@ -55,11 +42,12 @@ interface NoiseAvatarOptions {
55
42
  *
56
43
  * @param canvas Target HTMLCanvasElement (will be resized to `displaySize`).
57
44
  * @param seed Arbitrary string — same seed always produces the same image.
58
- * @param options Rendering options.
45
+ * @param options Avatar rendering options.
59
46
  */
60
47
  declare function renderNoiseAvatar(canvas: HTMLCanvasElement, seed: string, options?: NoiseAvatarOptions): void;
61
48
  /**
62
- * Create a Svelte action that renders a noise avatar and updates reactively.
49
+ * Svelte action that renders a noise avatar and updates reactively when
50
+ * `seed` changes.
63
51
  *
64
52
  * @example
65
53
  * ```svelte
@@ -70,4 +58,4 @@ declare function noiseAvatarAction(canvas: HTMLCanvasElement, seed: string, opti
70
58
  update(newSeed: string): void;
71
59
  };
72
60
 
73
- export { type NoiseAvatarOptions, hash32, hslToRgb, makePrng, noiseAvatarAction, renderNoiseAvatar };
61
+ export { type NoiseAvatarOptions, noiseAvatarAction, renderNoiseAvatar };
package/dist/index.js CHANGED
@@ -1,80 +1,43 @@
1
1
  // src/index.ts
2
- function hash32(str) {
3
- let h = 5381;
4
- for (let i = 0; i < str.length; i++) h = Math.imul(33, h) ^ str.charCodeAt(i);
5
- return h >>> 0;
6
- }
7
- function makePrng(seed) {
8
- let s = seed >>> 0;
9
- return () => {
10
- s = Math.imul(1664525, s) + 1013904223 >>> 0;
11
- return s / 4294967296;
2
+ import {
3
+ hash32,
4
+ makePrng,
5
+ hslToRgb,
6
+ makeValueNoiseSampler,
7
+ generateNoisePixels
8
+ } from "@ewanc26/noise";
9
+ import { renderNoise, noiseAction } from "@ewanc26/noise";
10
+ function toRenderOptions(opts) {
11
+ const colorMode = {
12
+ type: "hsl",
13
+ hueRange: opts.hueRange,
14
+ saturationRange: opts.saturationRange,
15
+ lightnessRange: opts.lightnessRange
12
16
  };
13
- }
14
- function hslToRgb(h, s, l) {
15
- const a = s * Math.min(l, 1 - l);
16
- const f = (n) => {
17
- const k = (n + h * 12) % 12;
18
- return l - a * Math.max(-1, Math.min(k - 3, 9 - k, 1));
17
+ return {
18
+ size: opts.displaySize ?? 64,
19
+ gridSize: opts.gridSize,
20
+ colorMode
19
21
  };
20
- return [Math.round(f(0) * 255), Math.round(f(8) * 255), Math.round(f(4) * 255)];
21
- }
22
- function smoothstep(t) {
23
- return t * t * (3 - 2 * t);
24
22
  }
25
23
  function renderNoiseAvatar(canvas, seed, options = {}) {
26
- const {
27
- gridSize = 5,
28
- displaySize = 64,
29
- hueRange = 60,
30
- saturationRange = [45, 70],
31
- lightnessRange = [40, 70]
32
- } = options;
33
- canvas.width = displaySize;
34
- canvas.height = displaySize;
35
- const ctx = canvas.getContext("2d");
36
- if (!ctx) return;
37
- const seedNum = hash32(seed);
38
- const rng = makePrng(seedNum);
39
- const baseHue = seedNum % 360;
40
- const G = gridSize + 1;
41
- const grid = Array.from({ length: G * G }, () => rng());
42
- const gridVal = (gx, gy) => grid[gy * G + gx];
43
- const imageData = ctx.createImageData(displaySize, displaySize);
44
- for (let py = 0; py < displaySize; py++) {
45
- for (let px = 0; px < displaySize; px++) {
46
- const fx = px / displaySize * gridSize;
47
- const fy = py / displaySize * gridSize;
48
- const gx = Math.floor(fx);
49
- const gy = Math.floor(fy);
50
- const tx = smoothstep(fx - gx);
51
- const ty = smoothstep(fy - gy);
52
- const v = (1 - ty) * ((1 - tx) * gridVal(gx, gy) + tx * gridVal(gx + 1, gy)) + ty * ((1 - tx) * gridVal(gx, gy + 1) + tx * gridVal(gx + 1, gy + 1));
53
- const hue = (baseHue + v * hueRange) % 360;
54
- const sat = saturationRange[0] + v * (saturationRange[1] - saturationRange[0]);
55
- const light = lightnessRange[0] + v * (lightnessRange[1] - lightnessRange[0]);
56
- const [r, g, b] = hslToRgb(hue / 360, sat / 100, light / 100);
57
- const i = (py * displaySize + px) * 4;
58
- imageData.data[i] = r;
59
- imageData.data[i + 1] = g;
60
- imageData.data[i + 2] = b;
61
- imageData.data[i + 3] = 255;
62
- }
63
- }
64
- ctx.putImageData(imageData, 0, 0);
24
+ renderNoise(canvas, seed, toRenderOptions(options));
65
25
  }
66
- function noiseAvatarAction(canvas, seed, options) {
67
- renderNoiseAvatar(canvas, seed, options);
26
+ function noiseAvatarAction(canvas, seed, options = {}) {
27
+ const params = { seed, ...toRenderOptions(options) };
28
+ const action = noiseAction(canvas, params);
68
29
  return {
69
30
  update(newSeed) {
70
- renderNoiseAvatar(canvas, newSeed, options);
31
+ action.update({ seed: newSeed, ...toRenderOptions(options) });
71
32
  }
72
33
  };
73
34
  }
74
35
  export {
36
+ generateNoisePixels,
75
37
  hash32,
76
38
  hslToRgb,
77
39
  makePrng,
40
+ makeValueNoiseSampler,
78
41
  noiseAvatarAction,
79
42
  renderNoiseAvatar
80
43
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ewanc26/noise-avatar",
3
- "version": "0.1.0",
4
- "description": "Deterministic value-noise avatar generation from a string seed. Zero dependencies, works in browsers and Node.js.",
3
+ "version": "0.2.1",
4
+ "description": "Deterministic value-noise avatar generation from a string seed. Thin wrapper around @ewanc26/noise. Zero extra dependencies, works in any environment with a Canvas API.",
5
5
  "author": "Ewan Croft",
6
6
  "license": "AGPL-3.0-only",
7
7
  "type": "module",
@@ -26,8 +26,11 @@
26
26
  "canvas",
27
27
  "deterministic"
28
28
  ],
29
+ "dependencies": {
30
+ "@ewanc26/noise": "^0.1.1"
31
+ },
29
32
  "devDependencies": {
30
- "tsup": "^8.5.0",
33
+ "tsup": "^8.5.1",
31
34
  "typescript": "^5.9.3"
32
35
  },
33
36
  "publishConfig": {