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 +22 -0
- package/README.md +122 -0
- package/dist/index.cjs +32 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/package.json +47 -0
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":"aAIO,SAASA,CAAAA,CAASC,EAAyB,CAChD,GAAI,OAAOA,CAAAA,EAAQ,QAAA,CACjB,MAAM,IAAI,KAAA,CAAM,CAAA,oBAAA,EAAuB,OAAOA,CAAG,CAAC,EAAE,CAAA,CAEtD,GAAI,CAAC,kBAAA,CAAmB,IAAA,CAAKA,CAAG,CAAA,CAC9B,MAAM,IAAI,MAAM,CAAA,oBAAA,EAAuBA,CAAG,EAAE,CAAA,CAE9C,GAAIA,EAAI,MAAA,CAAS,CAAA,GAAM,CAAA,CACrB,MAAM,IAAI,KAAA,CAAM,oCAAoCA,CAAG,CAAA,CAAE,CAAA,CAE3D,IAAMC,CAAAA,CAAM,IAAI,YAAYD,CAAAA,CAAI,MAAA,CAAS,CAAA,EAAK,CAAC,CAAA,CAC/C,IAAA,IAASE,EAAI,CAAA,CAAGA,CAAAA,CAAID,EAAI,MAAA,CAAQC,CAAAA,EAAAA,CAC9BD,EAAIC,CAAC,CAAA,CAAI,QAAA,CAASF,CAAAA,CAAI,KAAA,CAAM,CAAA,CAAIE,EAAI,CAAA,CAAG,CAAA,CAAIA,EAAI,CAAC,CAAA,CAAG,EAAE,CAAA,CAEvD,OAAOD,CACT,CCVA,SAASE,CAAAA,CAAQC,EAAWC,CAAAA,CAAqB,CAG/C,IAAMC,CAAAA,CAAU,IAAA,CAAK,IAAID,CAAAA,CAAK,IAAA,CAAK,GAAA,CAAI,CAAA,CAAGD,CAAC,CAAC,EAC5C,OAAI,IAAA,CAAK,GAAA,CAAIE,CAAAA,CAAUD,CAAG,CAAA,CAAI,KAAiB,CAAA,CACvCC,CAAAA,CAAUD,CAAAA,CAAOA,CAC3B,CAEA,SAASE,EAAWC,CAAAA,CAAWC,CAAAA,CAAWC,EAAmB,CAG3D,OAFIA,EAAI,CAAA,GAAGA,CAAAA,EAAK,CAAA,CAAA,CACZA,CAAAA,CAAI,CAAA,GAAGA,CAAAA,EAAK,GACZA,CAAAA,CAAI,CAAA,CAAI,EAAUF,CAAAA,CAAAA,CAAKC,CAAAA,CAAID,GAAK,CAAA,CAAIE,CAAAA,CACpCA,CAAAA,CAAI,CAAA,CAAI,CAAA,CAAUD,CAAAA,CAClBC,EAAI,CAAA,CAAI,CAAA,CAAUF,GAAKC,CAAAA,CAAID,CAAAA,GAAM,EAAI,CAAA,CAAIE,CAAAA,CAAAA,CAAK,CAAA,CAC3CF,CACT,CAEA,SAASG,EAASC,CAAAA,CAAWC,CAAAA,CAAWC,CAAAA,CAAqC,CAE3E,IAAMC,CAAAA,CAAKZ,EAAQS,CAAAA,CAAG,GAAG,CAAA,CACnBI,CAAAA,CAAKb,CAAAA,CAAQU,CAAAA,CAAG,GAAG,CAAA,CACnBI,CAAAA,CAAKd,EAAQW,CAAAA,CAAG,GAAG,EAEzB,GAAIE,CAAAA,GAAO,CAAA,CAAG,CACZ,IAAME,CAAAA,CAAID,EAAK,GAAA,CACf,OAAO,CAACC,CAAAA,CAAGA,CAAAA,CAAGA,CAAC,CACjB,CACA,IAAMT,CAAAA,CAAIQ,CAAAA,CAAK,EAAA,CAAMA,GAAM,CAAA,CAAID,CAAAA,CAAAA,CAAMC,EAAKD,CAAAA,CAAKC,CAAAA,CAAKD,EAC9CR,CAAAA,CAAI,CAAA,CAAIS,CAAAA,CAAKR,CAAAA,CACnB,OAAO,CACLF,EAAWC,CAAAA,CAAGC,CAAAA,CAAGM,CAAAA,CAAK,CAAA,CAAI,CAAC,CAAA,CAAI,IAC/BR,CAAAA,CAAWC,CAAAA,CAAGC,CAAAA,CAAGM,CAAE,CAAA,CAAI,GAAA,CACvBR,EAAWC,CAAAA,CAAGC,CAAAA,CAAGM,EAAK,CAAA,CAAI,CAAC,EAAI,GACjC,CACF,CAEA,SAASI,CAAAA,CAAS,CAAA,CAAWC,EAAWC,CAAAA,CAAqC,CAC3E,IAAMC,CAAAA,CAAK,CAAA,CAAI,IACTC,CAAAA,CAAKH,CAAAA,CAAI,GAAA,CACTI,CAAAA,CAAKH,CAAAA,CAAI,GAAA,CACThB,EAAM,IAAA,CAAK,GAAA,CAAIiB,EAAIC,CAAAA,CAAIC,CAAE,EACzBC,CAAAA,CAAM,IAAA,CAAK,GAAA,CAAIH,CAAAA,CAAIC,CAAAA,CAAIC,CAAE,EACzBV,CAAAA,CAAAA,CAAKT,CAAAA,CAAMoB,CAAAA,EAAO,CAAA,CACxB,GAAIpB,CAAAA,GAAQoB,EAAK,OAAO,CAAC,CAAA,CAAG,CAAA,CAAGX,CAAC,CAAA,CAEhC,IAAMY,CAAAA,CAAIrB,CAAAA,CAAMoB,EACVZ,CAAAA,CAAIC,CAAAA,CAAI,GAAMY,CAAAA,EAAK,CAAA,CAAIrB,CAAAA,CAAMoB,CAAAA,CAAAA,CAAOC,CAAAA,EAAKrB,CAAAA,CAAMoB,GACjDb,CAAAA,CACJ,OAAIP,IAAQiB,CAAAA,CACVV,CAAAA,CAAAA,CAAKW,EAAKC,CAAAA,EAAME,CAAAA,EAAKH,CAAAA,CAAKC,CAAAA,CAAK,CAAA,CAAI,CAAA,CAAA,CAC1BnB,IAAQkB,CAAAA,CACjBX,CAAAA,CAAAA,CAAKY,EAAKF,CAAAA,EAAMI,CAAAA,CAAI,EAEpBd,CAAAA,CAAAA,CAAKU,CAAAA,CAAKC,CAAAA,EAAMG,CAAAA,CAAI,CAAA,CAEf,CAACd,EAAI,CAAA,CAAGC,CAAAA,CAAGC,CAAC,CACrB,CAEO,SAASa,EAAUf,CAAAA,CAAWC,CAAAA,CAAWC,CAAAA,CAAmB,CACjE,GAAM,CAACc,EAAGR,CAAAA,CAAGC,CAAC,EAAIV,CAAAA,CAASC,CAAAA,CAAGC,EAAGC,CAAC,CAAA,CAE5Be,CAAAA,CAAK,IAAA,CAAK,GAAA,CAAI,GAAA,CAAK,KAAK,GAAA,CAAI,CAAA,CAAGD,CAAC,CAAC,CAAA,CACjCE,EAAK,IAAA,CAAK,GAAA,CAAI,GAAA,CAAK,IAAA,CAAK,GAAA,CAAI,CAAA,CAAGV,CAAC,CAAC,CAAA,CACjCW,EAAK,IAAA,CAAK,GAAA,CAAI,IAAK,IAAA,CAAK,GAAA,CAAI,CAAA,CAAGV,CAAC,CAAC,CAAA,CACjC,CAACN,CAAAA,CAAIC,CAAAA,CAAIC,CAAE,CAAA,CAAIE,CAAAA,CAASU,CAAAA,CAAIC,EAAIC,CAAE,CAAA,CACxC,OAAO,CAAA,IAAA,EAAO,IAAA,CAAK,KAAA,CAAMhB,EAAK,GAAG,CAAC,KAAK,IAAA,CAAK,KAAA,CAAMC,EAAK,GAAG,CAAC,CAAA,GAAA,EAAM,IAAA,CAAK,KAAA,CAAMC,CAAAA,CAAK,GAAG,CAAC,CAAA,EAAA,CACvF,CCpEA,IAAMe,CAAAA,CAAUxB,GAAcA,CAAAA,CAExByB,CAAAA,CAAczB,CAAAA,EAAc,CAChC,IAAM0B,CAAAA,CAAI1B,EAAI,CAAA,CACRE,CAAAA,CAAIF,EAAI,CAAA,CACd,OAAIE,EAAI,CAAA,CAAUF,CAAAA,CAAIE,CAAAA,CAAIA,CAAAA,CACnB,CAAA,CAAIwB,CAAAA,CAAIA,EAAIA,CAAAA,CAAI,CACzB,CAAA,CAEMC,CAAAA,CAAW3B,CAAAA,EAAcA,CAAAA,CAAIA,EAAIA,CAAAA,CAEjC4B,CAAAA,CAAW5B,CAAAA,EAAcA,CAAAA,CAAIA,CAAAA,CAAIA,CAAAA,CAAIA,EAAIA,CAAAA,CAEzC6B,CAAAA,CAAS,CAACC,CAAAA,CAAcjC,CAAAA,GAAgB,KAAK,KAAA,CAAOiC,CAAAA,CAAO,GAAA,CAAOjC,CAAG,CAAA,CAErEkC,CAAAA,CAAY3B,GACZA,CAAAA,EAAK,CAAA,CAAUA,EAAI,GAAA,CAChB,GAAA,CAAOA,EAAI,GAAA,CAGd4B,CAAAA,CAAc,CAACF,CAAAA,CAAcb,CAAAA,CAAapB,CAAAA,GAC9CgC,EAAOC,CAAAA,CAAMjC,CAAAA,CAAMoB,CAAG,CAAA,CAAIA,CAAAA,CAKfgB,EAAY,CAACC,CAAAA,CAAmBC,CAAAA,GAA6B,CACxE,IAAMC,CAAAA,CAASF,EAAY,CAAA,CACrBG,CAAAA,CAAaF,CAAAA,CAAY,CAAA,CAAI,EAAA,CACnC,OAAQC,GACN,KAAK,CAAA,CACH,OAAO,CAACE,CAAAA,CAAKC,IAAQ,CACnB,IAAMC,EAASF,CAAAA,CAAMD,CAAAA,CAAa,GAClC,OAAON,CAAAA,CAASP,CAAAA,CAAO,CAAA,CAAMe,CAAG,CAAA,CAAID,EAAMd,CAAAA,CAAOe,CAAG,EAAIC,CAAM,CAChE,EACF,KAAK,CAAA,CACH,OAAO,CAACF,CAAAA,CAAKC,CAAAA,GAAQ,CACnB,IAAMC,CAAAA,CAASF,EAAMD,CAAAA,CAAa,EAAA,CAClC,OAAON,CAAAA,CAASP,CAAAA,CAAO,CAAA,CAAMe,CAAG,CAAA,CAAID,CAAAA,CAAMd,EAAOe,CAAG,CAAA,CAAIC,CAAM,CAChE,CAAA,CACF,OACE,OAAO,CAACF,CAAAA,CAAKC,CAAAA,GAAQ,CACnB,IAAMC,EAASF,CAAAA,CAAMD,CAAAA,CAAa,GAC5BI,CAAAA,CAAchB,CAAAA,CAAWc,CAAG,CAAA,CAClC,OAAOR,CAAAA,CAASP,CAAAA,CAAO,CAAA,CAAMiB,CAAW,EAAIH,CAAAA,CAAMG,CAAAA,CAAcD,CAAM,CACxE,CAAA,CAEF,QACE,OAAO,CAACF,CAAAA,CAAKC,CAAAA,GAAQ,CACnB,IAAMC,EAASF,CAAAA,CAAMD,CAAAA,CAAa,GAAKR,CAAAA,CAAOK,CAAAA,CAAW,CAAG,CAAA,CAAI,EAAA,CAC1DO,CAAAA,CAAchB,CAAAA,CAAWc,CAAG,CAAA,CAClC,OAAOR,CAAAA,CAAAA,CAAU,CAAA,CAAMU,CAAAA,EAAeH,CAAAA,CAAMG,CAAAA,CAAcD,CAAM,CAClE,CACJ,CACF,CAAA,CAEME,CAAAA,CAAmBR,CAAAA,EACfA,CAAAA,GACD,EACI,CAACS,CAAAA,CAAOC,EAAKL,CAAAA,GAAQ,CAC1B,IAAME,CAAAA,CAAcb,CAAAA,CAAQW,CAAG,CAAA,CAC/B,OAAA,CAAQ,CAAA,CAAME,GAAeE,CAAAA,CAAQF,CAAAA,CAAcG,CACrD,CAAA,CAGO,CAACD,EAAOC,CAAAA,CAAKL,CAAAA,GAAQ,CAC1B,IAAME,CAAAA,CAAcd,CAAAA,CAAQY,CAAG,CAAA,CAC/B,OAAA,CAAQ,EAAME,CAAAA,EAAeE,CAAAA,CAAQF,EAAcG,CACrD,CAAA,CAIAC,CAAAA,CAAoBX,CAAAA,EAChBA,CAAAA,GACD,CAAA,CACI,CAACS,CAAAA,CAAOC,CAAAA,CAAKL,CAAAA,GAAQ,CAC1B,IAAME,CAAAA,CAAcb,EAAQW,CAAG,CAAA,CAC/B,OAAA,CAAQ,CAAA,CAAME,CAAAA,EAAeE,CAAAA,CAAQF,EAAcG,CACrD,CAAA,CAGO,CAACD,CAAAA,CAAOC,CAAAA,CAAKL,IAAQ,CAC1B,IAAME,CAAAA,CAAcjB,CAAAA,CAAOe,CAAG,CAAA,CAC9B,QAAQ,CAAA,CAAME,CAAAA,EAAeE,EAAQF,CAAAA,CAAcG,CACrD,EAMOE,CAAAA,CAAsBC,CAAAA,EAAkC,CACnE,IAAMC,CAAAA,CAAQzD,CAAAA,CAASwD,CAAO,CAAA,CAAE,OAAA,GAK1BlC,CAAAA,CAAKnB,CAAAA,EAAsB,CAC/B,IAAMgB,CAAAA,CAAIsC,CAAAA,CAAMtD,CAAC,CAAA,CACjB,GAAIgB,IAAM,MAAA,CACR,MAAM,IAAI,KAAA,CAAM,CAAA,sEAAA,EAAyEsC,CAAAA,CAAM,MAAM,CAAA,CAAA,CAAG,CAAA,CAE1G,OAAOtC,CACT,CAAA,CAEMuC,CAAAA,CAAahB,EAAUpB,CAAAA,CAAE,CAAC,EAAGA,CAAAA,CAAE,CAAC,EAAI,CAAC,CAAA,CACrCqC,CAAAA,CAAWrB,CAAAA,CAAOhB,CAAAA,CAAE,EAAE,EAAG,GAAG,CAAA,CAC5BsC,EAAiBnB,CAAAA,CAAYnB,CAAAA,CAAE,CAAC,CAAA,CAAG,EAAA,CAAI,IAAI,CAAA,CAC3CuC,CAAAA,CAAAA,CAAgB,EAAA,CAAKpB,EAAYnB,CAAAA,CAAE,CAAC,EAAG,EAAA,CAAI,EAAE,GAAK,CAAA,CAClDwC,CAAAA,CAAkBrB,CAAAA,CAAYnB,CAAAA,CAAE,CAAC,CAAA,CAAG,GAAI,EAAE,CAAA,CAC1CyC,CAAAA,CAAgB,IAAA,CAAK,GAAA,CACzBD,CAAAA,CAAkB,GAClBrB,CAAAA,CAAYnB,CAAAA,CAAE,EAAE,CAAA,CAAG,EAAA,CAAI,EAAE,CAC3B,CAAA,CAEM0C,CAAAA,CAAmBb,EAAgB7B,CAAAA,CAAE,CAAC,EAAI,CAAC,CAAA,CAC3C2C,CAAAA,CAAoBX,CAAAA,CAAiBhC,CAAAA,CAAE,CAAC,EAAI,CAAC,CAAA,CAEnD,OAAO,CACLM,CAAAA,CACE8B,EAAWC,CAAAA,CAAU,CAAC,CAAA,CACtBM,CAAAA,CAAkBH,CAAAA,CAAiBC,CAAAA,CAAe,CAAC,CAAA,CACnDC,CAAAA,CAAiBJ,EAAgBC,CAAAA,CAAc,CAAC,CAClD,CAAA,CACAjC,CAAAA,CACE8B,CAAAA,CAAWC,CAAAA,CAAU,EAAG,CAAA,CACxBM,EAAkBH,CAAAA,CAAiBC,CAAAA,CAAe,EAAG,CAAA,CACrDC,CAAAA,CAAiBJ,CAAAA,CAAgBC,EAAc,EAAG,CACpD,CAAA,CACAjC,CAAAA,CACE8B,CAAAA,CAAWC,CAAAA,CAAU,EAAG,CAAA,CACxBM,CAAAA,CAAkBH,EAAiBC,CAAAA,CAAe,EAAG,EACrDC,CAAAA,CAAiBJ,CAAAA,CAAgBC,CAAAA,CAAc,EAAG,CACpD,CAAA,CACAjC,EACE8B,CAAAA,CAAWC,CAAAA,CAAU,EAAG,CAAA,CACxBM,CAAAA,CAAkBH,CAAAA,CAAiBC,EAAe,EAAG,CAAA,CACrDC,CAAAA,CAAiBJ,CAAAA,CAAgBC,CAAAA,CAAc,EAAG,CACpD,CAAA,CACAjC,CAAAA,CACE8B,EAAWC,CAAAA,CAAU,CAAC,EACtBM,CAAAA,CAAkBH,CAAAA,CAAiBC,CAAAA,CAAe,CAAC,CAAA,CACnDH,CACF,CACF,CACF,ECjJO,IAAMM,CAAAA,CAAWV,CAAAA,EAA4B,CAClD,IAAMW,CAAAA,CAAkBZ,CAAAA,CAAmBC,CAAO,CAAA,CAClD,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wCAAA,EAWiCW,CAAAA,CAAE,CAAC,CAAC,CAAA;AAAA,wCAAA,EACJA,CAAAA,CAAE,CAAC,CAAC,CAAA;AAAA,wCAAA,EACJA,CAAAA,CAAE,CAAC,CAAC,CAAA;AAAA,wCAAA,EACJA,CAAAA,CAAE,CAAC,CAAC,CAAA;AAAA,sCAAA,EACNA,CAAAA,CAAE,CAAC,CAAC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA,CAgB5C,CAAA,CAEMC,CAAAA,CAAYtD,CAAAA,EAAsB,CACtC,GAAI,OAAO,MAAA,CAAW,GAAA,CACpB,OAAO,MAAA,CAAO,IAAA,CAAKA,CAAAA,CAAG,OAAO,CAAA,CAAE,QAAA,CAAS,QAAQ,CAAA,CAKlD,IAAM2C,CAAAA,CAAQ,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO3C,CAAC,CAAA,CACpCuD,CAAAA,CAAS,GACb,IAAA,IAASlE,CAAAA,CAAI,CAAA,CAAGA,CAAAA,CAAIsD,CAAAA,CAAM,MAAA,CAAQtD,IAAKkE,CAAAA,EAAU,MAAA,CAAO,YAAA,CAAaZ,CAAAA,CAAMtD,CAAC,CAAE,EAC9E,OAAO,IAAA,CAAKkE,CAAM,CACpB,CAAA,CAEaC,CAAAA,CAAed,CAAAA,EAC1B,CAAA,0BAAA,EAA6BY,CAAAA,CAASF,CAAAA,CAAQV,CAAO,CAAC,CAAC,CAAA","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"]}
|
package/dist/index.d.cts
ADDED
|
@@ -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.d.ts
ADDED
|
@@ -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
|
+
}
|