zero-deps-zorbs 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 zero-deps-zorbs contributors
4
+ Algorithm originally from Zora's @zoralabs/zorb (MIT, copyright Zora Labs).
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,122 @@
1
+ # zero-deps-zorbs
2
+
3
+ Tiny, zero-dependency generator for [Zora](https://github.com/ourzora/zorb)-style
4
+ gradient avatars from Ethereum addresses. Drop one in anywhere a user needs a
5
+ deterministic fallback PFP.
6
+
7
+ ```ts
8
+ import { zorbDataURI } from 'zero-deps-zorbs';
9
+
10
+ <img src={zorbDataURI('0xd8da6bf26964af9d7eed9e03e53415d37aa96045')} alt="" />
11
+ ```
12
+
13
+ Output is **byte-for-byte identical** to Zora's [`@zoralabs/zorb`](https://github.com/ourzora/zorb/tree/main/packages/zorb-web-component)
14
+ across every input we've tested (~2,300 addresses; see [Verification](#verification)).
15
+ Bundle is **3.6 KB minified**. No runtime dependencies.
16
+
17
+ ## What this is
18
+
19
+ A pure-function library that turns any 20-byte hex string into the same
20
+ 5-stop radial-gradient SVG zorb that Zora's library produces. Three exports:
21
+
22
+ ```ts
23
+ gradientForAddress(addr): [string, string, string, string, string] // 5 hsl() stops
24
+ zorbSVG(addr): string // full SVG markup
25
+ zorbDataURI(addr): string // data:image/svg+xml;base64,…
26
+ ```
27
+
28
+ Works in Node, Bun, edge runtimes, React Server Components, and the browser
29
+ without any setup. No DOM required, no React peer dep, no web-component
30
+ registration step — just functions.
31
+
32
+ ## Why this exists
33
+
34
+ Zora's [`@zoralabs/zorb`](https://github.com/ourzora/zorb) is the original
35
+ implementation. It's a Svelte-compiled web component that ships with two
36
+ runtime dependencies the algorithm doesn't actually need:
37
+
38
+ - **`@ethersproject/bytes`** — used solely to parse `0x…` hex into a byte
39
+ array. No `keccak256`, no signing, no blockchain primitives — just hex
40
+ parsing, which is ~10 lines of plain JS.
41
+ - **`tinycolor2`** — used solely to format `{h, s, l}` into an `hsl(H, S%, L%)`
42
+ string. No color picking, no manipulation — just string formatting (with
43
+ one HSL→RGB→HSL roundtrip we replicate exactly).
44
+
45
+ It also bundles the Svelte runtime to provide a `<zora-zorb>` custom element,
46
+ which is great if you want a custom element but pure overhead if you just
47
+ want the SVG.
48
+
49
+ `zero-deps-zorbs` is a re-implementation that strips all of that. The
50
+ gradient math and SVG template are ported verbatim from upstream's `lib.ts`
51
+ and `zorbImageDataURI.ts` so output matches byte-for-byte; the two
52
+ dependencies are replaced inline ([`bytes.ts`](src/bytes.ts),
53
+ [`hsl.ts`](src/hsl.ts)). The result is a 3.6 KB bundle with zero
54
+ `dependencies` in `package.json`, suitable as a fallback PFP on any site
55
+ without dragging in a Svelte runtime or an Ethereum library.
56
+
57
+ If you want the original web component or you're already inside a Zora app,
58
+ use [`@zoralabs/zorb`](https://www.npmjs.com/package/@zoralabs/zorb). If you
59
+ want pure functions in a tiny bundle, use this.
60
+
61
+ ## Install
62
+
63
+ ```sh
64
+ npm i zero-deps-zorbs
65
+ ```
66
+
67
+ ## Use
68
+
69
+ ```ts
70
+ import { zorbDataURI, zorbSVG, gradientForAddress } from 'zero-deps-zorbs';
71
+
72
+ // drop into <img>
73
+ <img src={zorbDataURI('0xd8da6bf26964af9d7eed9e03e53415d37aa96045')} alt="" />
74
+
75
+ // or render the SVG inline
76
+ element.innerHTML = zorbSVG('0xd8da…');
77
+
78
+ // or get the raw 5-stop HSL gradient
79
+ const [c0, c1, c2, c3, c4] = gradientForAddress('0xd8da…');
80
+ ```
81
+
82
+ Inputs are case-insensitive (mirrors `arrayify`'s behaviour). Anything that's
83
+ not a `0x`-prefixed even-length hex string throws — same contract as upstream.
84
+
85
+ ## Verification
86
+
87
+ The whole point of this package is identical output. That promise is
88
+ enforced by four independent checks, all run in CI:
89
+
90
+ | Layer | Command | What it does |
91
+ |---|---|---|
92
+ | 1. Parity tests | `npm test` | Vitest imports the real `@zoralabs/zorb` and asserts `gradientForAddress`, `zorbDataURI`, and the decoded SVG match across ~2,300 inputs. ~4,800 assertions; any single divergence fails the suite. |
93
+ | 2. Parity report | `npm run compare` | Same corpus, but collects every divergence into [`reports/parity-report.md`](reports/parity-report.md). Exits non-zero on any mismatch. |
94
+ | 3. Visual report | `npm run build-visual` | Renders 50 upstream-vs-ours pairs side-by-side in [`reports/visual.html`](reports/visual.html) with auto match/DIFFER indicators. |
95
+ | 4. Bundle audit | `npm run audit-dist` | Greps `dist/` for `ethers`, `tinycolor`, `keccak`, etc. Fails if any leaked, if size > 5 KB, or if `package.json`'s `dependencies` is non-empty. |
96
+
97
+ The corpus ([`test/corpus.ts`](test/corpus.ts)) is fully deterministic:
98
+ edge addresses (`0x00…00`, `0xff…ff`, alternating-bit patterns), famous
99
+ addresses, 2,000 Mulberry32-seeded pseudo-random addresses, and 100
100
+ addresses' worth of case variants. Same seed → same corpus → same result
101
+ every run.
102
+
103
+ Run everything end-to-end:
104
+
105
+ ```sh
106
+ npm run verify
107
+ ```
108
+
109
+ ## Credit
110
+
111
+ The gradient algorithm and the SVG template come from Zora's
112
+ [`@zoralabs/zorb`](https://github.com/ourzora/zorb) — MIT licensed,
113
+ copyright Zora Labs. This package is a re-implementation, not a fork:
114
+ it ships none of the upstream's runtime code, but the mathematical
115
+ behaviour is preserved exactly so the output is interchangeable.
116
+
117
+ If you ship `zero-deps-zorbs`, you're shipping Zora's design and Zora's
118
+ algorithm. Please credit them.
119
+
120
+ ## License
121
+
122
+ MIT.
package/dist/index.cjs ADDED
@@ -0,0 +1,32 @@
1
+ 'use strict';function S(r){if(typeof r!="string")throw new Error(`invalid hex string: ${String(r)}`);if(!/^0x[0-9a-fA-F]*$/.test(r))throw new Error(`invalid hex string: ${r}`);if(r.length%2!==0)throw new Error(`invalid hex string (odd length): ${r}`);let t=new Uint8Array((r.length-2)/2);for(let n=0;n<t.length;n++)t[n]=parseInt(r.slice(2+n*2,4+n*2),16);return t}function h(r,t){let n=Math.min(t,Math.max(0,r));return Math.abs(n-t)<1e-6?1:n%t/t}function p(r,t,n){return n<0&&(n+=1),n>1&&(n-=1),n<1/6?r+(t-r)*6*n:n<1/2?t:n<2/3?r+(t-r)*(2/3-n)*6:r}function v(r,t,n){let s=h(r,360),e=h(t,100),o=h(n,100);if(e===0){let a=o*255;return [a,a,a]}let u=o<.5?o*(1+e):o+e-o*e,i=2*o-u;return [p(i,u,s+1/3)*255,p(i,u,s)*255,p(i,u,s-1/3)*255]}function C(r,t,n){let s=r/255,e=t/255,o=n/255,u=Math.max(s,e,o),i=Math.min(s,e,o),a=(u+i)/2;if(u===i)return [0,0,a];let c=u-i,b=a>.5?c/(2-u-i):c/(u+i),m;return u===s?m=(e-o)/c+(e<o?6:0):u===e?m=(o-s)/c+2:m=(s-e)/c+4,[m/6,b,a]}function f(r,t,n){let[s,e,o]=v(r,t,n),u=Math.min(255,Math.max(0,s)),i=Math.min(255,Math.max(0,e)),a=Math.min(255,Math.max(0,o)),[c,b,m]=C(u,i,a);return `hsl(${Math.round(c*360)}, ${Math.round(b*100)}%, ${Math.round(m*100)}%)`}var l=r=>r,F=r=>{let t=r-1,n=r*2;return n<1?r*n*n:1+t*t*t*4},H=r=>r*r*r,x=r=>r*r*r*r*r,y=(r,t)=>Math.round(r/255*t),d=r=>r>=0?r%360:360+r%360,g=(r,t,n)=>y(r,n-t)+t,z=(r,t)=>{let n=r%4,s=t?1:-1;switch(n){case 0:return (e,o)=>{let u=e+s*10;return d(l(1-o)*e+l(o)*u)};case 1:return (e,o)=>{let u=e+s*30;return d(l(1-o)*e+l(o)*u)};case 2:return (e,o)=>{let u=e+s*50,i=F(o);return d(l(1-i)*e+i*u)};default:return (e,o)=>{let u=e+s*60*y(r,1)+30,i=F(o);return d((1-i)*e+i*u)}}},G=r=>r===0?(t,n,s)=>{let e=x(s);return (1-e)*t+e*n}:(t,n,s)=>{let e=H(s);return (1-e)*t+e*n},N=r=>r===0?(t,n,s)=>{let e=x(s);return (1-e)*t+e*n}:(t,n,s)=>{let e=l(s);return (1-e)*t+e*n},w=r=>{let t=S(r).reverse(),n=m=>{let M=t[m];if(M===void 0)throw new Error(`zero-deps-zorbs: address bytes too short (need at least 13 bytes, got ${t.length})`);return M},s=z(n(3),n(6)%2),e=y(n(12),360),o=g(n(2),32,69.5),u=(97+g(n(8),72,97))/2,i=g(n(7),81,97),a=Math.min(i-10,g(n(10),70,92)),c=G(n(5)%2),b=N(n(3)%2);return [f(s(e,0),b(i,a,1),c(o,u,1)),f(s(e,.1),b(i,a,.9),c(o,u,.9)),f(s(e,.7),b(i,a,.7),c(o,u,.7)),f(s(e,.9),b(i,a,.2),c(o,u,.2)),f(s(e,1),b(i,a,0),o)]};var $=r=>{let t=w(r);return `
2
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 110 110">
3
+ <defs>
4
+ <radialGradient
5
+ id="gzr"
6
+ gradientTransform="translate(66.4578 24.3575) scale(75.2908)"
7
+ gradientUnits="userSpaceOnUse"
8
+ r="1"
9
+ cx="0"
10
+ cy="0%"
11
+ >
12
+ <stop offset="15.62%" stop-color="${t[0]}" />
13
+ <stop offset="39.58%" stop-color="${t[1]}" />
14
+ <stop offset="72.92%" stop-color="${t[2]}" />
15
+ <stop offset="90.63%" stop-color="${t[3]}" />
16
+ <stop offset="100%" stop-color="${t[4]}" />
17
+ </radialGradient>
18
+ </defs>
19
+ <g transform="translate(5,5)">
20
+ <path
21
+ d="M100 50C100 22.3858 77.6142 0 50 0C22.3858 0 0 22.3858 0 50C0 77.6142 22.3858 100 50 100C77.6142 100 100 77.6142 100 50Z"
22
+ fill="url(#gzr)"
23
+ /><path
24
+ stroke="rgba(0,0,0,0.075)"
25
+ fill="transparent"
26
+ stroke-width="1"
27
+ d="M50,0.5c27.3,0,49.5,22.2,49.5,49.5S77.3,99.5,50,99.5S0.5,77.3,0.5,50S22.7,0.5,50,0.5z"
28
+ />
29
+ </g>
30
+ </svg>
31
+ `},A=r=>{if(typeof Buffer<"u")return Buffer.from(r,"utf-8").toString("base64");let t=new TextEncoder().encode(r),n="";for(let s=0;s<t.length;s++)n+=String.fromCharCode(t[s]);return btoa(n)},I=r=>`data:image/svg+xml;base64,${A($(r))}`;exports.gradientForAddress=w;exports.zorbDataURI=I;exports.zorbSVG=$;//# sourceMappingURL=index.cjs.map
32
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/bytes.ts","../src/hsl.ts","../src/gradient.ts","../src/svg.ts"],"names":["arrayify","hex","out","i","bound01","n","max","clamped","hueChannel","p","q","t","hslToRgb","h","s","l","hN","sN","lN","v","rgbToHsl","g","b","rN","gN","bN","min","d","hslString","r","rC","gC","bC","linear","cubicInOut","m","cubicIn","quintIn","bscale","byte","clampHue","bScaleRange","lerpHueFn","optionNum","direction","option","multiplier","hue","pct","endHue","lerpPercent","lerpLightnessFn","start","end","lerpSaturationFn","gradientForAddress","address","bytes","hueShiftFn","startHue","startLightness","endLightness","startSaturation","endSaturation","lightnessShiftFn","saturationShiftFn","zorbSVG","c","toBase64","binary","zorbDataURI"],"mappings":"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","file":"index.cjs","sourcesContent":["// Drop-in replacement for `arrayify` from @ethersproject/bytes,\n// scoped to the only thing this package needs: parsing 0x-prefixed hex\n// strings into a Uint8Array.\n\nexport function arrayify(hex: string): Uint8Array {\n if (typeof hex !== 'string') {\n throw new Error(`invalid hex string: ${String(hex)}`);\n }\n if (!/^0x[0-9a-fA-F]*$/.test(hex)) {\n throw new Error(`invalid hex string: ${hex}`);\n }\n if (hex.length % 2 !== 0) {\n throw new Error(`invalid hex string (odd length): ${hex}`);\n }\n const out = new Uint8Array((hex.length - 2) / 2);\n for (let i = 0; i < out.length; i++) {\n out[i] = parseInt(hex.slice(2 + i * 2, 4 + i * 2), 16);\n }\n return out;\n}\n","// Drop-in replacement for the single tinycolor2 call this package uses:\n// tinycolor({h, s, l}).toHslString()\n//\n// tinycolor doesn't just format the input — it pushes HSL → RGB → HSL,\n// clamps RGB to [0,255] (without rounding), then rounds h*360, s*100, l*100\n// to integers for the output string. To match its output byte-for-byte,\n// we reproduce that exact pipeline. The parity test (see test/parity.test.ts)\n// is the source of truth.\n\nfunction bound01(n: number, max: number): number {\n // Faithful port of tinycolor2's bound01 for numeric inputs.\n // (tinycolor also handles percentage strings; we never pass those.)\n const clamped = Math.min(max, Math.max(0, n));\n if (Math.abs(clamped - max) < 0.000001) return 1;\n return (clamped % max) / max;\n}\n\nfunction hueChannel(p: number, q: number, t: number): number {\n if (t < 0) t += 1;\n if (t > 1) t -= 1;\n if (t < 1 / 6) return p + (q - p) * 6 * t;\n if (t < 1 / 2) return q;\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;\n return p;\n}\n\nfunction hslToRgb(h: number, s: number, l: number): [number, number, number] {\n // h in [0,360], s/l in [0,100]; output r/g/b in [0,255] as floats.\n const hN = bound01(h, 360);\n const sN = bound01(s, 100);\n const lN = bound01(l, 100);\n\n if (sN === 0) {\n const v = lN * 255;\n return [v, v, v];\n }\n const q = lN < 0.5 ? lN * (1 + sN) : lN + sN - lN * sN;\n const p = 2 * lN - q;\n return [\n hueChannel(p, q, hN + 1 / 3) * 255,\n hueChannel(p, q, hN) * 255,\n hueChannel(p, q, hN - 1 / 3) * 255,\n ];\n}\n\nfunction rgbToHsl(r: number, g: number, b: number): [number, number, number] {\n const rN = r / 255;\n const gN = g / 255;\n const bN = b / 255;\n const max = Math.max(rN, gN, bN);\n const min = Math.min(rN, gN, bN);\n const l = (max + min) / 2;\n if (max === min) return [0, 0, l];\n\n const d = max - min;\n const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n let h: number;\n if (max === rN) {\n h = (gN - bN) / d + (gN < bN ? 6 : 0);\n } else if (max === gN) {\n h = (bN - rN) / d + 2;\n } else {\n h = (rN - gN) / d + 4;\n }\n return [h / 6, s, l];\n}\n\nexport function hslString(h: number, s: number, l: number): string {\n const [r, g, b] = hslToRgb(h, s, l);\n // tinycolor clamps RGB to [0,255] without rounding before round-tripping.\n const rC = Math.min(255, Math.max(0, r));\n const gC = Math.min(255, Math.max(0, g));\n const bC = Math.min(255, Math.max(0, b));\n const [hN, sN, lN] = rgbToHsl(rC, gC, bC);\n return `hsl(${Math.round(hN * 360)}, ${Math.round(sN * 100)}%, ${Math.round(lN * 100)}%)`;\n}\n","// Verbatim port of @zoralabs/zorb's lib.ts gradient algorithm.\n// Source: https://github.com/ourzora/zorb/blob/main/packages/zorb-web-component/src/lib.ts\n// Behaviour preserved exactly: same byte indices, same constants, same easing curves.\n\nimport { arrayify } from './bytes.js';\nimport { hslString } from './hsl.js';\n\nconst linear = (p: number) => p;\n\nconst cubicInOut = (p: number) => {\n const m = p - 1;\n const t = p * 2;\n if (t < 1) return p * t * t;\n return 1 + m * m * m * 4;\n};\n\nconst cubicIn = (p: number) => p * p * p;\n\nconst quintIn = (p: number) => p * p * p * p * p;\n\nconst bscale = (byte: number, max: number) => Math.round((byte / 255) * max);\n\nconst clampHue = (h: number) => {\n if (h >= 0) return h % 360.0;\n return 360 + (h % 360);\n};\n\nconst bScaleRange = (byte: number, min: number, max: number) =>\n bscale(byte, max - min) + min;\n\ntype HueFn = (hue: number, pct: number) => number;\ntype LerpFn = (start: number, end: number, pct: number) => number;\n\nexport const lerpHueFn = (optionNum: number, direction: number): HueFn => {\n const option = optionNum % 4;\n const multiplier = direction ? 1 : -1;\n switch (option) {\n case 0:\n return (hue, pct) => {\n const endHue = hue + multiplier * 10;\n return clampHue(linear(1.0 - pct) * hue + linear(pct) * endHue);\n };\n case 1:\n return (hue, pct) => {\n const endHue = hue + multiplier * 30;\n return clampHue(linear(1.0 - pct) * hue + linear(pct) * endHue);\n };\n case 2:\n return (hue, pct) => {\n const endHue = hue + multiplier * 50;\n const lerpPercent = cubicInOut(pct);\n return clampHue(linear(1.0 - lerpPercent) * hue + lerpPercent * endHue);\n };\n case 3:\n default:\n return (hue, pct) => {\n const endHue = hue + multiplier * 60 * bscale(optionNum, 1.0) + 30;\n const lerpPercent = cubicInOut(pct);\n return clampHue((1.0 - lerpPercent) * hue + lerpPercent * endHue);\n };\n }\n};\n\nconst lerpLightnessFn = (optionNum: number): LerpFn => {\n switch (optionNum) {\n case 0:\n return (start, end, pct) => {\n const lerpPercent = quintIn(pct);\n return (1.0 - lerpPercent) * start + lerpPercent * end;\n };\n case 1:\n default:\n return (start, end, pct) => {\n const lerpPercent = cubicIn(pct);\n return (1.0 - lerpPercent) * start + lerpPercent * end;\n };\n }\n};\n\nconst lerpSaturationFn = (optionNum: number): LerpFn => {\n switch (optionNum) {\n case 0:\n return (start, end, pct) => {\n const lerpPercent = quintIn(pct);\n return (1.0 - lerpPercent) * start + lerpPercent * end;\n };\n case 1:\n default:\n return (start, end, pct) => {\n const lerpPercent = linear(pct);\n return (1.0 - lerpPercent) * start + lerpPercent * end;\n };\n }\n};\n\nexport type ZorbGradient = readonly [string, string, string, string, string];\n\nexport const gradientForAddress = (address: string): ZorbGradient => {\n const bytes = arrayify(address).reverse();\n\n // Indexed access on a Uint8Array can be `number | undefined` under\n // noUncheckedIndexedAccess; we coerce because we know the corpus only\n // ever passes 20-byte addresses.\n const b = (i: number): number => {\n const v = bytes[i];\n if (v === undefined) {\n throw new Error(`zero-deps-zorbs: address bytes too short (need at least 13 bytes, got ${bytes.length})`);\n }\n return v;\n };\n\n const hueShiftFn = lerpHueFn(b(3), b(6) % 2);\n const startHue = bscale(b(12), 360);\n const startLightness = bScaleRange(b(2), 32, 69.5);\n const endLightness = (97 + bScaleRange(b(8), 72, 97)) / 2;\n const startSaturation = bScaleRange(b(7), 81, 97);\n const endSaturation = Math.min(\n startSaturation - 10,\n bScaleRange(b(10), 70, 92),\n );\n\n const lightnessShiftFn = lerpLightnessFn(b(5) % 2);\n const saturationShiftFn = lerpSaturationFn(b(3) % 2);\n\n return [\n hslString(\n hueShiftFn(startHue, 0),\n saturationShiftFn(startSaturation, endSaturation, 1),\n lightnessShiftFn(startLightness, endLightness, 1),\n ),\n hslString(\n hueShiftFn(startHue, 0.1),\n saturationShiftFn(startSaturation, endSaturation, 0.9),\n lightnessShiftFn(startLightness, endLightness, 0.9),\n ),\n hslString(\n hueShiftFn(startHue, 0.7),\n saturationShiftFn(startSaturation, endSaturation, 0.7),\n lightnessShiftFn(startLightness, endLightness, 0.7),\n ),\n hslString(\n hueShiftFn(startHue, 0.9),\n saturationShiftFn(startSaturation, endSaturation, 0.2),\n lightnessShiftFn(startLightness, endLightness, 0.2),\n ),\n hslString(\n hueShiftFn(startHue, 1),\n saturationShiftFn(startSaturation, endSaturation, 0),\n startLightness,\n ),\n ] as const;\n};\n","// SVG template — must match @zoralabs/zorb's zorbImageSVG byte-for-byte,\n// including leading/trailing whitespace inside the template literal.\n// Verified against upstream by test/parity.test.ts.\n\nimport { gradientForAddress, type ZorbGradient } from './gradient.js';\n\nexport const zorbSVG = (address: string): string => {\n const c: ZorbGradient = gradientForAddress(address);\n return `\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 110 110\">\n <defs>\n <radialGradient\n id=\"gzr\"\n gradientTransform=\"translate(66.4578 24.3575) scale(75.2908)\"\n gradientUnits=\"userSpaceOnUse\"\n r=\"1\"\n cx=\"0\"\n cy=\"0%\"\n >\n <stop offset=\"15.62%\" stop-color=\"${c[0]}\" />\n <stop offset=\"39.58%\" stop-color=\"${c[1]}\" />\n <stop offset=\"72.92%\" stop-color=\"${c[2]}\" />\n <stop offset=\"90.63%\" stop-color=\"${c[3]}\" />\n <stop offset=\"100%\" stop-color=\"${c[4]}\" />\n </radialGradient>\n </defs>\n <g transform=\"translate(5,5)\">\n <path\n d=\"M100 50C100 22.3858 77.6142 0 50 0C22.3858 0 0 22.3858 0 50C0 77.6142 22.3858 100 50 100C77.6142 100 100 77.6142 100 50Z\"\n fill=\"url(#gzr)\"\n /><path\n stroke=\"rgba(0,0,0,0.075)\"\n fill=\"transparent\"\n stroke-width=\"1\"\n d=\"M50,0.5c27.3,0,49.5,22.2,49.5,49.5S77.3,99.5,50,99.5S0.5,77.3,0.5,50S22.7,0.5,50,0.5z\"\n />\n </g>\n</svg>\n `;\n};\n\nconst toBase64 = (s: string): string => {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(s, 'utf-8').toString('base64');\n }\n // Browser fallback: encode as UTF-8 first, then btoa.\n // (btoa can't handle non-Latin1 directly, but the SVG template is ASCII so\n // a plain btoa would also work — the encode step is defensive.)\n const bytes = new TextEncoder().encode(s);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]!);\n return btoa(binary);\n};\n\nexport const zorbDataURI = (address: string): string =>\n `data:image/svg+xml;base64,${toBase64(zorbSVG(address))}`;\n"]}
@@ -0,0 +1,7 @@
1
+ type ZorbGradient = readonly [string, string, string, string, string];
2
+ declare const gradientForAddress: (address: string) => ZorbGradient;
3
+
4
+ declare const zorbSVG: (address: string) => string;
5
+ declare const zorbDataURI: (address: string) => string;
6
+
7
+ export { type ZorbGradient, gradientForAddress, zorbDataURI, zorbSVG };
@@ -0,0 +1,7 @@
1
+ type ZorbGradient = readonly [string, string, string, string, string];
2
+ declare const gradientForAddress: (address: string) => ZorbGradient;
3
+
4
+ declare const zorbSVG: (address: string) => string;
5
+ declare const zorbDataURI: (address: string) => string;
6
+
7
+ export { type ZorbGradient, gradientForAddress, zorbDataURI, zorbSVG };
package/dist/index.js ADDED
@@ -0,0 +1,32 @@
1
+ function S(r){if(typeof r!="string")throw new Error(`invalid hex string: ${String(r)}`);if(!/^0x[0-9a-fA-F]*$/.test(r))throw new Error(`invalid hex string: ${r}`);if(r.length%2!==0)throw new Error(`invalid hex string (odd length): ${r}`);let t=new Uint8Array((r.length-2)/2);for(let n=0;n<t.length;n++)t[n]=parseInt(r.slice(2+n*2,4+n*2),16);return t}function h(r,t){let n=Math.min(t,Math.max(0,r));return Math.abs(n-t)<1e-6?1:n%t/t}function p(r,t,n){return n<0&&(n+=1),n>1&&(n-=1),n<1/6?r+(t-r)*6*n:n<1/2?t:n<2/3?r+(t-r)*(2/3-n)*6:r}function v(r,t,n){let s=h(r,360),e=h(t,100),o=h(n,100);if(e===0){let a=o*255;return [a,a,a]}let u=o<.5?o*(1+e):o+e-o*e,i=2*o-u;return [p(i,u,s+1/3)*255,p(i,u,s)*255,p(i,u,s-1/3)*255]}function C(r,t,n){let s=r/255,e=t/255,o=n/255,u=Math.max(s,e,o),i=Math.min(s,e,o),a=(u+i)/2;if(u===i)return [0,0,a];let c=u-i,b=a>.5?c/(2-u-i):c/(u+i),m;return u===s?m=(e-o)/c+(e<o?6:0):u===e?m=(o-s)/c+2:m=(s-e)/c+4,[m/6,b,a]}function f(r,t,n){let[s,e,o]=v(r,t,n),u=Math.min(255,Math.max(0,s)),i=Math.min(255,Math.max(0,e)),a=Math.min(255,Math.max(0,o)),[c,b,m]=C(u,i,a);return `hsl(${Math.round(c*360)}, ${Math.round(b*100)}%, ${Math.round(m*100)}%)`}var l=r=>r,F=r=>{let t=r-1,n=r*2;return n<1?r*n*n:1+t*t*t*4},H=r=>r*r*r,x=r=>r*r*r*r*r,y=(r,t)=>Math.round(r/255*t),d=r=>r>=0?r%360:360+r%360,g=(r,t,n)=>y(r,n-t)+t,z=(r,t)=>{let n=r%4,s=t?1:-1;switch(n){case 0:return (e,o)=>{let u=e+s*10;return d(l(1-o)*e+l(o)*u)};case 1:return (e,o)=>{let u=e+s*30;return d(l(1-o)*e+l(o)*u)};case 2:return (e,o)=>{let u=e+s*50,i=F(o);return d(l(1-i)*e+i*u)};default:return (e,o)=>{let u=e+s*60*y(r,1)+30,i=F(o);return d((1-i)*e+i*u)}}},G=r=>r===0?(t,n,s)=>{let e=x(s);return (1-e)*t+e*n}:(t,n,s)=>{let e=H(s);return (1-e)*t+e*n},N=r=>r===0?(t,n,s)=>{let e=x(s);return (1-e)*t+e*n}:(t,n,s)=>{let e=l(s);return (1-e)*t+e*n},w=r=>{let t=S(r).reverse(),n=m=>{let M=t[m];if(M===void 0)throw new Error(`zero-deps-zorbs: address bytes too short (need at least 13 bytes, got ${t.length})`);return M},s=z(n(3),n(6)%2),e=y(n(12),360),o=g(n(2),32,69.5),u=(97+g(n(8),72,97))/2,i=g(n(7),81,97),a=Math.min(i-10,g(n(10),70,92)),c=G(n(5)%2),b=N(n(3)%2);return [f(s(e,0),b(i,a,1),c(o,u,1)),f(s(e,.1),b(i,a,.9),c(o,u,.9)),f(s(e,.7),b(i,a,.7),c(o,u,.7)),f(s(e,.9),b(i,a,.2),c(o,u,.2)),f(s(e,1),b(i,a,0),o)]};var $=r=>{let t=w(r);return `
2
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 110 110">
3
+ <defs>
4
+ <radialGradient
5
+ id="gzr"
6
+ gradientTransform="translate(66.4578 24.3575) scale(75.2908)"
7
+ gradientUnits="userSpaceOnUse"
8
+ r="1"
9
+ cx="0"
10
+ cy="0%"
11
+ >
12
+ <stop offset="15.62%" stop-color="${t[0]}" />
13
+ <stop offset="39.58%" stop-color="${t[1]}" />
14
+ <stop offset="72.92%" stop-color="${t[2]}" />
15
+ <stop offset="90.63%" stop-color="${t[3]}" />
16
+ <stop offset="100%" stop-color="${t[4]}" />
17
+ </radialGradient>
18
+ </defs>
19
+ <g transform="translate(5,5)">
20
+ <path
21
+ d="M100 50C100 22.3858 77.6142 0 50 0C22.3858 0 0 22.3858 0 50C0 77.6142 22.3858 100 50 100C77.6142 100 100 77.6142 100 50Z"
22
+ fill="url(#gzr)"
23
+ /><path
24
+ stroke="rgba(0,0,0,0.075)"
25
+ fill="transparent"
26
+ stroke-width="1"
27
+ d="M50,0.5c27.3,0,49.5,22.2,49.5,49.5S77.3,99.5,50,99.5S0.5,77.3,0.5,50S22.7,0.5,50,0.5z"
28
+ />
29
+ </g>
30
+ </svg>
31
+ `},A=r=>{if(typeof Buffer<"u")return Buffer.from(r,"utf-8").toString("base64");let t=new TextEncoder().encode(r),n="";for(let s=0;s<t.length;s++)n+=String.fromCharCode(t[s]);return btoa(n)},I=r=>`data:image/svg+xml;base64,${A($(r))}`;export{w as gradientForAddress,I as zorbDataURI,$ as zorbSVG};//# sourceMappingURL=index.js.map
32
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/bytes.ts","../src/hsl.ts","../src/gradient.ts","../src/svg.ts"],"names":["arrayify","hex","out","i","bound01","n","max","clamped","hueChannel","p","q","t","hslToRgb","h","s","l","hN","sN","lN","v","rgbToHsl","g","b","rN","gN","bN","min","d","hslString","r","rC","gC","bC","linear","cubicInOut","m","cubicIn","quintIn","bscale","byte","clampHue","bScaleRange","lerpHueFn","optionNum","direction","option","multiplier","hue","pct","endHue","lerpPercent","lerpLightnessFn","start","end","lerpSaturationFn","gradientForAddress","address","bytes","hueShiftFn","startHue","startLightness","endLightness","startSaturation","endSaturation","lightnessShiftFn","saturationShiftFn","zorbSVG","c","toBase64","binary","zorbDataURI"],"mappings":"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","file":"index.js","sourcesContent":["// Drop-in replacement for `arrayify` from @ethersproject/bytes,\n// scoped to the only thing this package needs: parsing 0x-prefixed hex\n// strings into a Uint8Array.\n\nexport function arrayify(hex: string): Uint8Array {\n if (typeof hex !== 'string') {\n throw new Error(`invalid hex string: ${String(hex)}`);\n }\n if (!/^0x[0-9a-fA-F]*$/.test(hex)) {\n throw new Error(`invalid hex string: ${hex}`);\n }\n if (hex.length % 2 !== 0) {\n throw new Error(`invalid hex string (odd length): ${hex}`);\n }\n const out = new Uint8Array((hex.length - 2) / 2);\n for (let i = 0; i < out.length; i++) {\n out[i] = parseInt(hex.slice(2 + i * 2, 4 + i * 2), 16);\n }\n return out;\n}\n","// Drop-in replacement for the single tinycolor2 call this package uses:\n// tinycolor({h, s, l}).toHslString()\n//\n// tinycolor doesn't just format the input — it pushes HSL → RGB → HSL,\n// clamps RGB to [0,255] (without rounding), then rounds h*360, s*100, l*100\n// to integers for the output string. To match its output byte-for-byte,\n// we reproduce that exact pipeline. The parity test (see test/parity.test.ts)\n// is the source of truth.\n\nfunction bound01(n: number, max: number): number {\n // Faithful port of tinycolor2's bound01 for numeric inputs.\n // (tinycolor also handles percentage strings; we never pass those.)\n const clamped = Math.min(max, Math.max(0, n));\n if (Math.abs(clamped - max) < 0.000001) return 1;\n return (clamped % max) / max;\n}\n\nfunction hueChannel(p: number, q: number, t: number): number {\n if (t < 0) t += 1;\n if (t > 1) t -= 1;\n if (t < 1 / 6) return p + (q - p) * 6 * t;\n if (t < 1 / 2) return q;\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;\n return p;\n}\n\nfunction hslToRgb(h: number, s: number, l: number): [number, number, number] {\n // h in [0,360], s/l in [0,100]; output r/g/b in [0,255] as floats.\n const hN = bound01(h, 360);\n const sN = bound01(s, 100);\n const lN = bound01(l, 100);\n\n if (sN === 0) {\n const v = lN * 255;\n return [v, v, v];\n }\n const q = lN < 0.5 ? lN * (1 + sN) : lN + sN - lN * sN;\n const p = 2 * lN - q;\n return [\n hueChannel(p, q, hN + 1 / 3) * 255,\n hueChannel(p, q, hN) * 255,\n hueChannel(p, q, hN - 1 / 3) * 255,\n ];\n}\n\nfunction rgbToHsl(r: number, g: number, b: number): [number, number, number] {\n const rN = r / 255;\n const gN = g / 255;\n const bN = b / 255;\n const max = Math.max(rN, gN, bN);\n const min = Math.min(rN, gN, bN);\n const l = (max + min) / 2;\n if (max === min) return [0, 0, l];\n\n const d = max - min;\n const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n let h: number;\n if (max === rN) {\n h = (gN - bN) / d + (gN < bN ? 6 : 0);\n } else if (max === gN) {\n h = (bN - rN) / d + 2;\n } else {\n h = (rN - gN) / d + 4;\n }\n return [h / 6, s, l];\n}\n\nexport function hslString(h: number, s: number, l: number): string {\n const [r, g, b] = hslToRgb(h, s, l);\n // tinycolor clamps RGB to [0,255] without rounding before round-tripping.\n const rC = Math.min(255, Math.max(0, r));\n const gC = Math.min(255, Math.max(0, g));\n const bC = Math.min(255, Math.max(0, b));\n const [hN, sN, lN] = rgbToHsl(rC, gC, bC);\n return `hsl(${Math.round(hN * 360)}, ${Math.round(sN * 100)}%, ${Math.round(lN * 100)}%)`;\n}\n","// Verbatim port of @zoralabs/zorb's lib.ts gradient algorithm.\n// Source: https://github.com/ourzora/zorb/blob/main/packages/zorb-web-component/src/lib.ts\n// Behaviour preserved exactly: same byte indices, same constants, same easing curves.\n\nimport { arrayify } from './bytes.js';\nimport { hslString } from './hsl.js';\n\nconst linear = (p: number) => p;\n\nconst cubicInOut = (p: number) => {\n const m = p - 1;\n const t = p * 2;\n if (t < 1) return p * t * t;\n return 1 + m * m * m * 4;\n};\n\nconst cubicIn = (p: number) => p * p * p;\n\nconst quintIn = (p: number) => p * p * p * p * p;\n\nconst bscale = (byte: number, max: number) => Math.round((byte / 255) * max);\n\nconst clampHue = (h: number) => {\n if (h >= 0) return h % 360.0;\n return 360 + (h % 360);\n};\n\nconst bScaleRange = (byte: number, min: number, max: number) =>\n bscale(byte, max - min) + min;\n\ntype HueFn = (hue: number, pct: number) => number;\ntype LerpFn = (start: number, end: number, pct: number) => number;\n\nexport const lerpHueFn = (optionNum: number, direction: number): HueFn => {\n const option = optionNum % 4;\n const multiplier = direction ? 1 : -1;\n switch (option) {\n case 0:\n return (hue, pct) => {\n const endHue = hue + multiplier * 10;\n return clampHue(linear(1.0 - pct) * hue + linear(pct) * endHue);\n };\n case 1:\n return (hue, pct) => {\n const endHue = hue + multiplier * 30;\n return clampHue(linear(1.0 - pct) * hue + linear(pct) * endHue);\n };\n case 2:\n return (hue, pct) => {\n const endHue = hue + multiplier * 50;\n const lerpPercent = cubicInOut(pct);\n return clampHue(linear(1.0 - lerpPercent) * hue + lerpPercent * endHue);\n };\n case 3:\n default:\n return (hue, pct) => {\n const endHue = hue + multiplier * 60 * bscale(optionNum, 1.0) + 30;\n const lerpPercent = cubicInOut(pct);\n return clampHue((1.0 - lerpPercent) * hue + lerpPercent * endHue);\n };\n }\n};\n\nconst lerpLightnessFn = (optionNum: number): LerpFn => {\n switch (optionNum) {\n case 0:\n return (start, end, pct) => {\n const lerpPercent = quintIn(pct);\n return (1.0 - lerpPercent) * start + lerpPercent * end;\n };\n case 1:\n default:\n return (start, end, pct) => {\n const lerpPercent = cubicIn(pct);\n return (1.0 - lerpPercent) * start + lerpPercent * end;\n };\n }\n};\n\nconst lerpSaturationFn = (optionNum: number): LerpFn => {\n switch (optionNum) {\n case 0:\n return (start, end, pct) => {\n const lerpPercent = quintIn(pct);\n return (1.0 - lerpPercent) * start + lerpPercent * end;\n };\n case 1:\n default:\n return (start, end, pct) => {\n const lerpPercent = linear(pct);\n return (1.0 - lerpPercent) * start + lerpPercent * end;\n };\n }\n};\n\nexport type ZorbGradient = readonly [string, string, string, string, string];\n\nexport const gradientForAddress = (address: string): ZorbGradient => {\n const bytes = arrayify(address).reverse();\n\n // Indexed access on a Uint8Array can be `number | undefined` under\n // noUncheckedIndexedAccess; we coerce because we know the corpus only\n // ever passes 20-byte addresses.\n const b = (i: number): number => {\n const v = bytes[i];\n if (v === undefined) {\n throw new Error(`zero-deps-zorbs: address bytes too short (need at least 13 bytes, got ${bytes.length})`);\n }\n return v;\n };\n\n const hueShiftFn = lerpHueFn(b(3), b(6) % 2);\n const startHue = bscale(b(12), 360);\n const startLightness = bScaleRange(b(2), 32, 69.5);\n const endLightness = (97 + bScaleRange(b(8), 72, 97)) / 2;\n const startSaturation = bScaleRange(b(7), 81, 97);\n const endSaturation = Math.min(\n startSaturation - 10,\n bScaleRange(b(10), 70, 92),\n );\n\n const lightnessShiftFn = lerpLightnessFn(b(5) % 2);\n const saturationShiftFn = lerpSaturationFn(b(3) % 2);\n\n return [\n hslString(\n hueShiftFn(startHue, 0),\n saturationShiftFn(startSaturation, endSaturation, 1),\n lightnessShiftFn(startLightness, endLightness, 1),\n ),\n hslString(\n hueShiftFn(startHue, 0.1),\n saturationShiftFn(startSaturation, endSaturation, 0.9),\n lightnessShiftFn(startLightness, endLightness, 0.9),\n ),\n hslString(\n hueShiftFn(startHue, 0.7),\n saturationShiftFn(startSaturation, endSaturation, 0.7),\n lightnessShiftFn(startLightness, endLightness, 0.7),\n ),\n hslString(\n hueShiftFn(startHue, 0.9),\n saturationShiftFn(startSaturation, endSaturation, 0.2),\n lightnessShiftFn(startLightness, endLightness, 0.2),\n ),\n hslString(\n hueShiftFn(startHue, 1),\n saturationShiftFn(startSaturation, endSaturation, 0),\n startLightness,\n ),\n ] as const;\n};\n","// SVG template — must match @zoralabs/zorb's zorbImageSVG byte-for-byte,\n// including leading/trailing whitespace inside the template literal.\n// Verified against upstream by test/parity.test.ts.\n\nimport { gradientForAddress, type ZorbGradient } from './gradient.js';\n\nexport const zorbSVG = (address: string): string => {\n const c: ZorbGradient = gradientForAddress(address);\n return `\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 110 110\">\n <defs>\n <radialGradient\n id=\"gzr\"\n gradientTransform=\"translate(66.4578 24.3575) scale(75.2908)\"\n gradientUnits=\"userSpaceOnUse\"\n r=\"1\"\n cx=\"0\"\n cy=\"0%\"\n >\n <stop offset=\"15.62%\" stop-color=\"${c[0]}\" />\n <stop offset=\"39.58%\" stop-color=\"${c[1]}\" />\n <stop offset=\"72.92%\" stop-color=\"${c[2]}\" />\n <stop offset=\"90.63%\" stop-color=\"${c[3]}\" />\n <stop offset=\"100%\" stop-color=\"${c[4]}\" />\n </radialGradient>\n </defs>\n <g transform=\"translate(5,5)\">\n <path\n d=\"M100 50C100 22.3858 77.6142 0 50 0C22.3858 0 0 22.3858 0 50C0 77.6142 22.3858 100 50 100C77.6142 100 100 77.6142 100 50Z\"\n fill=\"url(#gzr)\"\n /><path\n stroke=\"rgba(0,0,0,0.075)\"\n fill=\"transparent\"\n stroke-width=\"1\"\n d=\"M50,0.5c27.3,0,49.5,22.2,49.5,49.5S77.3,99.5,50,99.5S0.5,77.3,0.5,50S22.7,0.5,50,0.5z\"\n />\n </g>\n</svg>\n `;\n};\n\nconst toBase64 = (s: string): string => {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(s, 'utf-8').toString('base64');\n }\n // Browser fallback: encode as UTF-8 first, then btoa.\n // (btoa can't handle non-Latin1 directly, but the SVG template is ASCII so\n // a plain btoa would also work — the encode step is defensive.)\n const bytes = new TextEncoder().encode(s);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]!);\n return btoa(binary);\n};\n\nexport const zorbDataURI = (address: string): string =>\n `data:image/svg+xml;base64,${toBase64(zorbSVG(address))}`;\n"]}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "zero-deps-zorbs",
3
+ "version": "0.1.0",
4
+ "license": "MIT",
5
+ "description": "Zero-dependency Zorb PFP generator. Byte-for-byte identical output to @zoralabs/zorb.",
6
+ "keywords": ["zorb", "pfp", "avatar", "ethereum", "svg", "fallback"],
7
+ "author": "ripe <unripeengine@gmail.com>",
8
+ "homepage": "https://github.com/ripe0x/zero-deps-zorbs#readme",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/ripe0x/zero-deps-zorbs.git"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/ripe0x/zero-deps-zorbs/issues"
15
+ },
16
+ "type": "module",
17
+ "main": "./dist/index.cjs",
18
+ "module": "./dist/index.js",
19
+ "types": "./dist/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "import": "./dist/index.js",
24
+ "require": "./dist/index.cjs"
25
+ }
26
+ },
27
+ "files": ["dist", "README.md", "LICENSE"],
28
+ "sideEffects": false,
29
+ "scripts": {
30
+ "build": "tsup",
31
+ "test": "vitest run",
32
+ "typecheck": "tsc --noEmit",
33
+ "compare": "tsx scripts/compare.ts",
34
+ "build-visual": "tsx scripts/build-visual.ts",
35
+ "audit-dist": "tsx scripts/audit-dist.ts",
36
+ "verify": "npm run typecheck && npm run test && npm run build && npm run audit-dist && npm run compare && npm run build-visual"
37
+ },
38
+ "dependencies": {},
39
+ "devDependencies": {
40
+ "@types/node": "^20.0.0",
41
+ "@zoralabs/zorb": "0.1.0",
42
+ "tsup": "^8.3.0",
43
+ "tsx": "^4.19.0",
44
+ "typescript": "^5.7.0",
45
+ "vitest": "^2.1.0"
46
+ }
47
+ }