hashvatar 0.1.0 → 0.1.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.
Files changed (3) hide show
  1. package/dist/index.cjs +132 -35
  2. package/dist/index.js +132 -35
  3. package/package.json +3 -3
package/dist/index.cjs CHANGED
@@ -155,7 +155,85 @@ var SHAPES = [
155
155
  [[0.15, 0.2], [0.55, 0.08], [0.92, 0.35], [0.78, 0.75], [0.4, 0.92], [0.2, 0.6]],
156
156
  [[0.45, 0.08], [0.82, 0.3], [0.7, 0.85], [0.3, 0.88], [0.08, 0.5], [0.25, 0.25]]
157
157
  ];
158
- function drawBlurredShape(ctx, path, size, tx, ty, rotate, scale, fillStyle, offsetX, offsetY) {
158
+ var _filterSupported = null;
159
+ function hasFilterBlur() {
160
+ if (_filterSupported !== null) return _filterSupported;
161
+ try {
162
+ const c = document.createElement("canvas");
163
+ c.width = 30;
164
+ c.height = 30;
165
+ const x = c.getContext("2d");
166
+ x.fillStyle = "#fff";
167
+ x.fillRect(0, 0, 30, 30);
168
+ x.filter = "blur(6px)";
169
+ x.fillStyle = "#000";
170
+ x.fillRect(12, 12, 4, 4);
171
+ _filterSupported = x.getImageData(22, 22, 1, 1).data[0] < 255;
172
+ x.filter = "none";
173
+ } catch {
174
+ _filterSupported = false;
175
+ }
176
+ return _filterSupported;
177
+ }
178
+ function boxBlurCanvas(ctx, w, h, radius, passes = 3) {
179
+ const r = Math.max(1, Math.round((Math.sqrt(4 * radius * radius + 1) - 1) / 2));
180
+ const imgData = ctx.getImageData(0, 0, w, h);
181
+ const s = imgData.data;
182
+ const d = new Uint8ClampedArray(s.length);
183
+ const diam = r * 2 + 1;
184
+ const inv = 1 / diam;
185
+ for (let pass = 0; pass < passes; pass++) {
186
+ for (let y = 0; y < h; y++) {
187
+ const row = y * w;
188
+ let rs = 0, gs = 0, bs = 0, as = 0;
189
+ for (let dx = -r; dx <= r; dx++) {
190
+ const i = row + Math.max(0, Math.min(w - 1, dx)) << 2;
191
+ rs += s[i];
192
+ gs += s[i | 1];
193
+ bs += s[i | 2];
194
+ as += s[i | 3];
195
+ }
196
+ for (let x = 0; x < w; x++) {
197
+ const o = row + x << 2;
198
+ d[o] = rs * inv;
199
+ d[o | 1] = gs * inv;
200
+ d[o | 2] = bs * inv;
201
+ d[o | 3] = as * inv;
202
+ const ai = row + Math.min(w - 1, x + r + 1) << 2;
203
+ const ri = row + Math.max(0, x - r) << 2;
204
+ rs += s[ai] - s[ri];
205
+ gs += s[ai | 1] - s[ri | 1];
206
+ bs += s[ai | 2] - s[ri | 2];
207
+ as += s[ai | 3] - s[ri | 3];
208
+ }
209
+ }
210
+ for (let x = 0; x < w; x++) {
211
+ let rs = 0, gs = 0, bs = 0, as = 0;
212
+ for (let dy = -r; dy <= r; dy++) {
213
+ const i = Math.max(0, Math.min(h - 1, dy)) * w + x << 2;
214
+ rs += d[i];
215
+ gs += d[i | 1];
216
+ bs += d[i | 2];
217
+ as += d[i | 3];
218
+ }
219
+ for (let y = 0; y < h; y++) {
220
+ const o = y * w + x << 2;
221
+ s[o] = rs * inv;
222
+ s[o | 1] = gs * inv;
223
+ s[o | 2] = bs * inv;
224
+ s[o | 3] = as * inv;
225
+ const ai = Math.min(h - 1, y + r + 1) * w + x << 2;
226
+ const ri = Math.max(0, y - r) * w + x << 2;
227
+ rs += d[ai] - d[ri];
228
+ gs += d[ai | 1] - d[ri | 1];
229
+ bs += d[ai | 2] - d[ri | 2];
230
+ as += d[ai | 3] - d[ri | 3];
231
+ }
232
+ }
233
+ }
234
+ ctx.putImageData(imgData, 0, 0);
235
+ }
236
+ function drawShape(ctx, path, size, tx, ty, rotate, scale, fillStyle, offsetX, offsetY) {
159
237
  const cx = size / 2;
160
238
  const cy = size / 2;
161
239
  ctx.save();
@@ -174,11 +252,19 @@ function drawBlurredShape(ctx, path, size, tx, ty, rotate, scale, fillStyle, off
174
252
  ctx.fill();
175
253
  ctx.restore();
176
254
  }
255
+ function getDevicePixelRatio() {
256
+ if (typeof window === "undefined" || !window.devicePixelRatio) return 1;
257
+ return Math.min(window.devicePixelRatio, 3);
258
+ }
177
259
  function renderGradient(canvas, { size, colors, animated = false, seeds }) {
178
260
  if (colors.length < 4) return null;
179
- canvas.width = size;
180
- canvas.height = size;
261
+ const dpr = getDevicePixelRatio();
262
+ canvas.width = size * dpr;
263
+ canvas.height = size * dpr;
264
+ canvas.style.width = `${size}px`;
265
+ canvas.style.height = `${size}px`;
181
266
  const ctx = canvas.getContext("2d");
267
+ ctx.scale(dpr, dpr);
182
268
  const mix = seeds[0].toString() + seeds[1].toString() + seeds[2].toString() + seeds[3].toString();
183
269
  const allSeeds = hashToSeeds(mix, 24);
184
270
  const layers = [0, 1, 2, 3, 4, 5].map((i) => {
@@ -200,22 +286,26 @@ function renderGradient(canvas, { size, colors, animated = false, seeds }) {
200
286
  { composite: "overlay", alpha: 0.4 },
201
287
  { composite: "soft-light", alpha: 0.6 }
202
288
  ];
203
- const blur = Math.max(8, Math.round(size * 0.21));
289
+ const blur = Math.max(2, Math.round(size * 0.21));
204
290
  const pad = Math.ceil(blur * 1.9);
291
+ const useFilter = hasFilterBlur();
205
292
  const ROT_SPEEDS = [0.5, 0.6, 0.45, 0.55, 0.5, 0.65];
206
293
  const DRIFT_AMP = size * 0.18;
207
294
  const DRIFT_FREQS = [0.5, 0.45, 0.4, 0.48, 0.52, 0.38];
208
295
  const DRIFT_PHASE_OFFSETS = [0, 1, 2, 0.5, 1.5, 3];
209
296
  const PHASE_SPEED = 1.2;
297
+ const w = size + pad * 2;
298
+ const h = size + pad * 2;
299
+ const animResScale = !useFilter && animated ? 0.5 : 1;
300
+ const offCanvas = document.createElement("canvas");
301
+ offCanvas.width = w * dpr * animResScale;
302
+ offCanvas.height = h * dpr * animResScale;
303
+ const offCtx = offCanvas.getContext("2d");
304
+ offCtx.scale(dpr * animResScale, dpr * animResScale);
210
305
  const draw = (phase2) => {
211
306
  ctx.clearRect(0, 0, size, size);
212
307
  ctx.fillStyle = hex0;
213
308
  ctx.fillRect(0, 0, size, size);
214
- const w = size + pad * 2;
215
- const h = size + pad * 2;
216
- const offCtx = document.createElement("canvas").getContext("2d");
217
- offCtx.canvas.width = w;
218
- offCtx.canvas.height = h;
219
309
  for (let i = 0; i < 6; i++) {
220
310
  const layer = layers[i];
221
311
  const rot = layer.rotate + (animated ? phase2 * ROT_SPEEDS[i] : 0);
@@ -226,24 +316,22 @@ function renderGradient(canvas, { size, colors, animated = false, seeds }) {
226
316
  const opts = LAYER_OPTS[i];
227
317
  const hex = hexColors[i % 3];
228
318
  offCtx.clearRect(0, 0, w, h);
229
- drawBlurredShape(
230
- offCtx,
231
- SHAPES[i],
232
- size,
233
- layer.tx + driftX,
234
- layer.ty + driftY,
235
- rot,
236
- scale,
237
- hex,
238
- pad,
239
- pad
240
- );
241
- ctx.save();
242
- ctx.filter = `blur(${blur}px)`;
243
- ctx.globalCompositeOperation = opts.composite;
244
- ctx.globalAlpha = opts.alpha;
245
- ctx.drawImage(offCtx.canvas, 0, 0, w, h, -pad, -pad, w, h);
246
- ctx.restore();
319
+ drawShape(offCtx, SHAPES[i], size, layer.tx + driftX, layer.ty + driftY, rot, scale, hex, pad, pad);
320
+ if (useFilter) {
321
+ ctx.save();
322
+ ctx.filter = `blur(${blur * dpr}px)`;
323
+ ctx.globalCompositeOperation = opts.composite;
324
+ ctx.globalAlpha = opts.alpha;
325
+ ctx.drawImage(offCanvas, 0, 0, offCanvas.width, offCanvas.height, -pad, -pad, w, h);
326
+ ctx.restore();
327
+ } else {
328
+ boxBlurCanvas(offCtx, offCanvas.width, offCanvas.height, blur * dpr * 1.4 * animResScale, animResScale < 1 ? 2 : 3);
329
+ ctx.save();
330
+ ctx.globalCompositeOperation = opts.composite;
331
+ ctx.globalAlpha = opts.alpha;
332
+ ctx.drawImage(offCanvas, 0, 0, offCanvas.width, offCanvas.height, -pad, -pad, w, h);
333
+ ctx.restore();
334
+ }
247
335
  }
248
336
  ctx.globalCompositeOperation = "source-over";
249
337
  ctx.globalAlpha = 1;
@@ -283,27 +371,36 @@ function hexToRgb2(hex) {
283
371
  const n = parseInt(hex.replace("#", ""), 16);
284
372
  return { r: n >> 16 & 255, g: n >> 8 & 255, b: n & 255 };
285
373
  }
374
+ function getDevicePixelRatio2() {
375
+ if (typeof window === "undefined" || !window.devicePixelRatio) return 1;
376
+ return Math.min(window.devicePixelRatio, 3);
377
+ }
286
378
  function renderDither(canvas, { size, colors, dotScale: dotScaleOpt, animated = false, seeds }) {
287
- canvas.width = size;
288
- canvas.height = size;
379
+ const dpr = getDevicePixelRatio2();
380
+ const sizePx = Math.round(size * dpr);
381
+ canvas.width = sizePx;
382
+ canvas.height = sizePx;
383
+ canvas.style.width = `${size}px`;
384
+ canvas.style.height = `${size}px`;
289
385
  const ctx = canvas.getContext("2d");
290
- const dotScale = dotScaleOpt ?? Math.max(2, Math.round(size / 35));
386
+ const dotScaleLogical = dotScaleOpt ?? Math.max(1, Math.round(size / 35));
387
+ const dotScale = Math.max(1, Math.round(dotScaleLogical * dpr));
291
388
  const colA = hexToRgb2(oklchToHex(colors[0]));
292
389
  const colB = hexToRgb2(oklchToHex(colors[Math.min(1, colors.length - 1)]));
293
390
  const baseAngle = seeds[0] * Math.PI * 2;
294
391
  const falloff = 0.55 + seeds[1] * 0.25;
295
392
  const swirlSpeed = 0.45;
296
393
  const padding = 1;
297
- const gridSize = Math.ceil(size / dotScale) + padding * 2;
394
+ const gridSize = Math.ceil(sizePx / dotScale) + padding * 2;
298
395
  const cellPhase = (gx, gy) => ((gx * 31 + gy * 17) * (seeds[2] * 1e3 + 1) + (seeds[3] * 1e3 | 0)) % 1e3 / 1e3 * Math.PI * 2;
299
396
  const cellAmp = (gx, gy) => 0.035 + (gx * 7 + gy * 13 + seeds[2] * 50 | 0) % 55 / 1100;
300
397
  const draw = (phase2) => {
301
- const img = ctx.createImageData(size, size);
398
+ const img = ctx.createImageData(sizePx, sizePx);
302
399
  const d = img.data;
303
400
  const angle = baseAngle + (animated ? phase2 * swirlSpeed : 0);
304
401
  const cosA = Math.cos(angle);
305
402
  const sinA = Math.sin(angle);
306
- for (let i = 0; i < size * size * 4; i += 4) {
403
+ for (let i = 0; i < sizePx * sizePx * 4; i += 4) {
307
404
  d[i] = colB.r;
308
405
  d[i + 1] = colB.g;
309
406
  d[i + 2] = colB.b;
@@ -329,8 +426,8 @@ function renderDither(canvas, { size, colors, dotScale: dotScaleOpt, animated =
329
426
  for (let px = 0; px < dotScale; px++) {
330
427
  const x = (gx - padding) * dotScale + px;
331
428
  const y = (gy - padding) * dotScale + py;
332
- if (x < 0 || y < 0 || x >= size || y >= size) continue;
333
- const idx = (y * size + x) * 4;
429
+ if (x < 0 || y < 0 || x >= sizePx || y >= sizePx) continue;
430
+ const idx = (y * sizePx + x) * 4;
334
431
  d[idx] = colA.r;
335
432
  d[idx + 1] = colA.g;
336
433
  d[idx + 2] = colA.b;
package/dist/index.js CHANGED
@@ -121,7 +121,85 @@ var SHAPES = [
121
121
  [[0.15, 0.2], [0.55, 0.08], [0.92, 0.35], [0.78, 0.75], [0.4, 0.92], [0.2, 0.6]],
122
122
  [[0.45, 0.08], [0.82, 0.3], [0.7, 0.85], [0.3, 0.88], [0.08, 0.5], [0.25, 0.25]]
123
123
  ];
124
- function drawBlurredShape(ctx, path, size, tx, ty, rotate, scale, fillStyle, offsetX, offsetY) {
124
+ var _filterSupported = null;
125
+ function hasFilterBlur() {
126
+ if (_filterSupported !== null) return _filterSupported;
127
+ try {
128
+ const c = document.createElement("canvas");
129
+ c.width = 30;
130
+ c.height = 30;
131
+ const x = c.getContext("2d");
132
+ x.fillStyle = "#fff";
133
+ x.fillRect(0, 0, 30, 30);
134
+ x.filter = "blur(6px)";
135
+ x.fillStyle = "#000";
136
+ x.fillRect(12, 12, 4, 4);
137
+ _filterSupported = x.getImageData(22, 22, 1, 1).data[0] < 255;
138
+ x.filter = "none";
139
+ } catch {
140
+ _filterSupported = false;
141
+ }
142
+ return _filterSupported;
143
+ }
144
+ function boxBlurCanvas(ctx, w, h, radius, passes = 3) {
145
+ const r = Math.max(1, Math.round((Math.sqrt(4 * radius * radius + 1) - 1) / 2));
146
+ const imgData = ctx.getImageData(0, 0, w, h);
147
+ const s = imgData.data;
148
+ const d = new Uint8ClampedArray(s.length);
149
+ const diam = r * 2 + 1;
150
+ const inv = 1 / diam;
151
+ for (let pass = 0; pass < passes; pass++) {
152
+ for (let y = 0; y < h; y++) {
153
+ const row = y * w;
154
+ let rs = 0, gs = 0, bs = 0, as = 0;
155
+ for (let dx = -r; dx <= r; dx++) {
156
+ const i = row + Math.max(0, Math.min(w - 1, dx)) << 2;
157
+ rs += s[i];
158
+ gs += s[i | 1];
159
+ bs += s[i | 2];
160
+ as += s[i | 3];
161
+ }
162
+ for (let x = 0; x < w; x++) {
163
+ const o = row + x << 2;
164
+ d[o] = rs * inv;
165
+ d[o | 1] = gs * inv;
166
+ d[o | 2] = bs * inv;
167
+ d[o | 3] = as * inv;
168
+ const ai = row + Math.min(w - 1, x + r + 1) << 2;
169
+ const ri = row + Math.max(0, x - r) << 2;
170
+ rs += s[ai] - s[ri];
171
+ gs += s[ai | 1] - s[ri | 1];
172
+ bs += s[ai | 2] - s[ri | 2];
173
+ as += s[ai | 3] - s[ri | 3];
174
+ }
175
+ }
176
+ for (let x = 0; x < w; x++) {
177
+ let rs = 0, gs = 0, bs = 0, as = 0;
178
+ for (let dy = -r; dy <= r; dy++) {
179
+ const i = Math.max(0, Math.min(h - 1, dy)) * w + x << 2;
180
+ rs += d[i];
181
+ gs += d[i | 1];
182
+ bs += d[i | 2];
183
+ as += d[i | 3];
184
+ }
185
+ for (let y = 0; y < h; y++) {
186
+ const o = y * w + x << 2;
187
+ s[o] = rs * inv;
188
+ s[o | 1] = gs * inv;
189
+ s[o | 2] = bs * inv;
190
+ s[o | 3] = as * inv;
191
+ const ai = Math.min(h - 1, y + r + 1) * w + x << 2;
192
+ const ri = Math.max(0, y - r) * w + x << 2;
193
+ rs += d[ai] - d[ri];
194
+ gs += d[ai | 1] - d[ri | 1];
195
+ bs += d[ai | 2] - d[ri | 2];
196
+ as += d[ai | 3] - d[ri | 3];
197
+ }
198
+ }
199
+ }
200
+ ctx.putImageData(imgData, 0, 0);
201
+ }
202
+ function drawShape(ctx, path, size, tx, ty, rotate, scale, fillStyle, offsetX, offsetY) {
125
203
  const cx = size / 2;
126
204
  const cy = size / 2;
127
205
  ctx.save();
@@ -140,11 +218,19 @@ function drawBlurredShape(ctx, path, size, tx, ty, rotate, scale, fillStyle, off
140
218
  ctx.fill();
141
219
  ctx.restore();
142
220
  }
221
+ function getDevicePixelRatio() {
222
+ if (typeof window === "undefined" || !window.devicePixelRatio) return 1;
223
+ return Math.min(window.devicePixelRatio, 3);
224
+ }
143
225
  function renderGradient(canvas, { size, colors, animated = false, seeds }) {
144
226
  if (colors.length < 4) return null;
145
- canvas.width = size;
146
- canvas.height = size;
227
+ const dpr = getDevicePixelRatio();
228
+ canvas.width = size * dpr;
229
+ canvas.height = size * dpr;
230
+ canvas.style.width = `${size}px`;
231
+ canvas.style.height = `${size}px`;
147
232
  const ctx = canvas.getContext("2d");
233
+ ctx.scale(dpr, dpr);
148
234
  const mix = seeds[0].toString() + seeds[1].toString() + seeds[2].toString() + seeds[3].toString();
149
235
  const allSeeds = hashToSeeds(mix, 24);
150
236
  const layers = [0, 1, 2, 3, 4, 5].map((i) => {
@@ -166,22 +252,26 @@ function renderGradient(canvas, { size, colors, animated = false, seeds }) {
166
252
  { composite: "overlay", alpha: 0.4 },
167
253
  { composite: "soft-light", alpha: 0.6 }
168
254
  ];
169
- const blur = Math.max(8, Math.round(size * 0.21));
255
+ const blur = Math.max(2, Math.round(size * 0.21));
170
256
  const pad = Math.ceil(blur * 1.9);
257
+ const useFilter = hasFilterBlur();
171
258
  const ROT_SPEEDS = [0.5, 0.6, 0.45, 0.55, 0.5, 0.65];
172
259
  const DRIFT_AMP = size * 0.18;
173
260
  const DRIFT_FREQS = [0.5, 0.45, 0.4, 0.48, 0.52, 0.38];
174
261
  const DRIFT_PHASE_OFFSETS = [0, 1, 2, 0.5, 1.5, 3];
175
262
  const PHASE_SPEED = 1.2;
263
+ const w = size + pad * 2;
264
+ const h = size + pad * 2;
265
+ const animResScale = !useFilter && animated ? 0.5 : 1;
266
+ const offCanvas = document.createElement("canvas");
267
+ offCanvas.width = w * dpr * animResScale;
268
+ offCanvas.height = h * dpr * animResScale;
269
+ const offCtx = offCanvas.getContext("2d");
270
+ offCtx.scale(dpr * animResScale, dpr * animResScale);
176
271
  const draw = (phase2) => {
177
272
  ctx.clearRect(0, 0, size, size);
178
273
  ctx.fillStyle = hex0;
179
274
  ctx.fillRect(0, 0, size, size);
180
- const w = size + pad * 2;
181
- const h = size + pad * 2;
182
- const offCtx = document.createElement("canvas").getContext("2d");
183
- offCtx.canvas.width = w;
184
- offCtx.canvas.height = h;
185
275
  for (let i = 0; i < 6; i++) {
186
276
  const layer = layers[i];
187
277
  const rot = layer.rotate + (animated ? phase2 * ROT_SPEEDS[i] : 0);
@@ -192,24 +282,22 @@ function renderGradient(canvas, { size, colors, animated = false, seeds }) {
192
282
  const opts = LAYER_OPTS[i];
193
283
  const hex = hexColors[i % 3];
194
284
  offCtx.clearRect(0, 0, w, h);
195
- drawBlurredShape(
196
- offCtx,
197
- SHAPES[i],
198
- size,
199
- layer.tx + driftX,
200
- layer.ty + driftY,
201
- rot,
202
- scale,
203
- hex,
204
- pad,
205
- pad
206
- );
207
- ctx.save();
208
- ctx.filter = `blur(${blur}px)`;
209
- ctx.globalCompositeOperation = opts.composite;
210
- ctx.globalAlpha = opts.alpha;
211
- ctx.drawImage(offCtx.canvas, 0, 0, w, h, -pad, -pad, w, h);
212
- ctx.restore();
285
+ drawShape(offCtx, SHAPES[i], size, layer.tx + driftX, layer.ty + driftY, rot, scale, hex, pad, pad);
286
+ if (useFilter) {
287
+ ctx.save();
288
+ ctx.filter = `blur(${blur * dpr}px)`;
289
+ ctx.globalCompositeOperation = opts.composite;
290
+ ctx.globalAlpha = opts.alpha;
291
+ ctx.drawImage(offCanvas, 0, 0, offCanvas.width, offCanvas.height, -pad, -pad, w, h);
292
+ ctx.restore();
293
+ } else {
294
+ boxBlurCanvas(offCtx, offCanvas.width, offCanvas.height, blur * dpr * 1.4 * animResScale, animResScale < 1 ? 2 : 3);
295
+ ctx.save();
296
+ ctx.globalCompositeOperation = opts.composite;
297
+ ctx.globalAlpha = opts.alpha;
298
+ ctx.drawImage(offCanvas, 0, 0, offCanvas.width, offCanvas.height, -pad, -pad, w, h);
299
+ ctx.restore();
300
+ }
213
301
  }
214
302
  ctx.globalCompositeOperation = "source-over";
215
303
  ctx.globalAlpha = 1;
@@ -249,27 +337,36 @@ function hexToRgb2(hex) {
249
337
  const n = parseInt(hex.replace("#", ""), 16);
250
338
  return { r: n >> 16 & 255, g: n >> 8 & 255, b: n & 255 };
251
339
  }
340
+ function getDevicePixelRatio2() {
341
+ if (typeof window === "undefined" || !window.devicePixelRatio) return 1;
342
+ return Math.min(window.devicePixelRatio, 3);
343
+ }
252
344
  function renderDither(canvas, { size, colors, dotScale: dotScaleOpt, animated = false, seeds }) {
253
- canvas.width = size;
254
- canvas.height = size;
345
+ const dpr = getDevicePixelRatio2();
346
+ const sizePx = Math.round(size * dpr);
347
+ canvas.width = sizePx;
348
+ canvas.height = sizePx;
349
+ canvas.style.width = `${size}px`;
350
+ canvas.style.height = `${size}px`;
255
351
  const ctx = canvas.getContext("2d");
256
- const dotScale = dotScaleOpt ?? Math.max(2, Math.round(size / 35));
352
+ const dotScaleLogical = dotScaleOpt ?? Math.max(1, Math.round(size / 35));
353
+ const dotScale = Math.max(1, Math.round(dotScaleLogical * dpr));
257
354
  const colA = hexToRgb2(oklchToHex(colors[0]));
258
355
  const colB = hexToRgb2(oklchToHex(colors[Math.min(1, colors.length - 1)]));
259
356
  const baseAngle = seeds[0] * Math.PI * 2;
260
357
  const falloff = 0.55 + seeds[1] * 0.25;
261
358
  const swirlSpeed = 0.45;
262
359
  const padding = 1;
263
- const gridSize = Math.ceil(size / dotScale) + padding * 2;
360
+ const gridSize = Math.ceil(sizePx / dotScale) + padding * 2;
264
361
  const cellPhase = (gx, gy) => ((gx * 31 + gy * 17) * (seeds[2] * 1e3 + 1) + (seeds[3] * 1e3 | 0)) % 1e3 / 1e3 * Math.PI * 2;
265
362
  const cellAmp = (gx, gy) => 0.035 + (gx * 7 + gy * 13 + seeds[2] * 50 | 0) % 55 / 1100;
266
363
  const draw = (phase2) => {
267
- const img = ctx.createImageData(size, size);
364
+ const img = ctx.createImageData(sizePx, sizePx);
268
365
  const d = img.data;
269
366
  const angle = baseAngle + (animated ? phase2 * swirlSpeed : 0);
270
367
  const cosA = Math.cos(angle);
271
368
  const sinA = Math.sin(angle);
272
- for (let i = 0; i < size * size * 4; i += 4) {
369
+ for (let i = 0; i < sizePx * sizePx * 4; i += 4) {
273
370
  d[i] = colB.r;
274
371
  d[i + 1] = colB.g;
275
372
  d[i + 2] = colB.b;
@@ -295,8 +392,8 @@ function renderDither(canvas, { size, colors, dotScale: dotScaleOpt, animated =
295
392
  for (let px = 0; px < dotScale; px++) {
296
393
  const x = (gx - padding) * dotScale + px;
297
394
  const y = (gy - padding) * dotScale + py;
298
- if (x < 0 || y < 0 || x >= size || y >= size) continue;
299
- const idx = (y * size + x) * 4;
395
+ if (x < 0 || y < 0 || x >= sizePx || y >= sizePx) continue;
396
+ const idx = (y * sizePx + x) * 4;
300
397
  d[idx] = colA.r;
301
398
  d[idx + 1] = colA.g;
302
399
  d[idx + 2] = colA.b;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hashvatar",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Deterministic avatar generation from any hash string. Zero dependencies.",
5
5
  "author": "Médhy",
6
6
  "license": "MIT",
@@ -27,7 +27,7 @@
27
27
  "scripts": {
28
28
  "build": "tsup",
29
29
  "dev": "tsup --watch",
30
- "demo": "npx serve . -p 5000",
30
+ "demo": "npx serve . -l tcp://0.0.0.0:5000",
31
31
  "prepublishOnly": "npm run build"
32
32
  },
33
33
  "devDependencies": {
@@ -57,6 +57,6 @@
57
57
  ],
58
58
  "repository": {
59
59
  "type": "git",
60
- "url": "https://github.com/medhychabour/hashvatar"
60
+ "url": "git+https://github.com/medhychabour/hashvatar.git"
61
61
  }
62
62
  }