Skip to content

Commit

Permalink
Improve Blobbie Algo (#4159)
Browse files Browse the repository at this point in the history
![image](https://github.com/user-attachments/assets/cfc34112-3b94-4125-8aba-4a065d7c9ec2)
![image](https://github.com/user-attachments/assets/9daf26b0-fde8-4a77-bebf-a77f94d444f2)
![image](https://github.com/user-attachments/assets/91c4ceb1-c3c0-4be6-a654-d233b699495a)
![image](https://github.com/user-attachments/assets/7a298ad2-7fa4-4967-a7ea-7e9ec2fcf7be)

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to improve the Blobbie algorithm for generating unique gradient avatars based on provided addresses.

### Detailed summary
- Updated color calculation logic for better color pairing
- Removed unused `nearestColor` function
- Refactored color and position calculations for Blobbie avatar
- Adjusted ellipse positions and sizes for better visual representation

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
  • Loading branch information
gregfromstl committed Aug 17, 2024
1 parent 355795a commit cf4443a
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 50 deletions.
5 changes: 5 additions & 0 deletions .changeset/honest-laws-taste.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"thirdweb": patch
---

Improves the Blobbie algorithm
123 changes: 73 additions & 50 deletions packages/thirdweb/src/react/web/ui/ConnectWallet/Blobbie.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,10 @@
"use client";
import { hexToNumber } from "@noble/curves/abstract/utils";
import { useId, useMemo } from "react";
import type { Address } from "viem";

const colorSet = [
"#ef4444",
"#f97316",
"#f59e0b",
"#eab308",
"#84cc16",
"#06b6d4",
"#3b82f6",
"#a855f7",
"#ec4899",
"#ec4899",
"#f43f5e",
];
import { type Address, numberToHex } from "viem";

// Distance between 2 colors (in RGB)
type Color = [number, number, number];
function distance(a: Color, b: Color) {
return Math.sqrt(
(a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2 + (a[2] - b[2]) ** 2,
);
}
function hexToRgb(hex: string) {
return [
Number(hexToNumber(hex.slice(0, 2))),
Expand All @@ -32,20 +13,6 @@ function hexToRgb(hex: string) {
] satisfies [number, number, number];
}

function nearestColor(colorHex: string) {
let lowest = Number.POSITIVE_INFINITY;
let tmp: number;
let index = 0;
colorSet.forEach((el, i) => {
tmp = distance(hexToRgb(colorHex), hexToRgb(el.replace("#", "")));
if (tmp < lowest) {
lowest = tmp;
index = i;
}
});
return colorSet[index] as string;
}

/**
* A unique gradient avatar based on the provided address.
* @param props The component props.
Expand All @@ -54,17 +21,34 @@ function nearestColor(colorHex: string) {
*/
export function Blobbie(props: { address: Address; size: number }) {
const id = useId();
const colors = useMemo(() => {
const _colors: string[] = [];
let i = 2;
while (i <= 30) {
const color = nearestColor(props.address.slice(i, i + 6));
_colors.push(color);
const colors: [string, string, string] = useMemo(() => {
const color = props.address.slice(2, 8);
const rgb = hexToRgb(color);

// To get well-paired colors, we use the first rgb hex sequence as our main color then find its two best pairs (split color wheel into thirds)
// To prevent extremely dark colors, which tend to clash, we don't allow values less than 55
const pairing1 = rgb.map((n) => (n + 85 > 255 ? n + 85 - 200 : n + 85));
const pairing2 = rgb.map((n) => (n - 85 < 55 ? n - 85 + 200 : n - 85));
return [
color,
pairing1.map((n) => numberToHex(n).replace("0x", "")).join(""),
pairing2.map((n) => numberToHex(n).replace("0x", "")).join(""),
];
}, [props.address]);

const positions: [Color, Color, Color, Color, Color] = useMemo(() => {
const _positions: Color[] = [];
let i = 8;
while (i < 44) {
const values = hexToRgb(props.address.slice(i, i + 6));
_positions.push(values);

Check warning on line 44 in packages/thirdweb/src/react/web/ui/ConnectWallet/Blobbie.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/ConnectWallet/Blobbie.tsx#L24-L44

Added lines #L24 - L44 were not covered by tests
i += 6;
}
return _colors;
return _positions as [Color, Color, Color, Color, Color];

Check warning on line 47 in packages/thirdweb/src/react/web/ui/ConnectWallet/Blobbie.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/ConnectWallet/Blobbie.tsx#L47

Added line #L47 was not covered by tests
}, [props.address]);

console.log(colors);

Check warning on line 51 in packages/thirdweb/src/react/web/ui/ConnectWallet/Blobbie.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/ConnectWallet/Blobbie.tsx#L50-L51

Added lines #L50 - L51 were not covered by tests
return (
<svg
height={`${props.size}px`}
Expand All @@ -89,23 +73,62 @@ export function Blobbie(props: { address: Address; size: number }) {
>
<stop
offset="0%"
style={{ stopColor: `${color}`, stopOpacity: 1 }}
style={{ stopColor: `#${color}`, stopOpacity: 0.9 }}

Check warning on line 76 in packages/thirdweb/src/react/web/ui/ConnectWallet/Blobbie.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/ConnectWallet/Blobbie.tsx#L76

Added line #L76 was not covered by tests
/>
<stop
offset="100%"
style={{ stopColor: `${color}`, stopOpacity: 0 }}
style={{ stopColor: `#${color}`, stopOpacity: 0 }}

Check warning on line 80 in packages/thirdweb/src/react/web/ui/ConnectWallet/Blobbie.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/ConnectWallet/Blobbie.tsx#L80

Added line #L80 was not covered by tests
/>
</radialGradient>
);
})}
</defs>
<ellipse cx="100" cy="100" rx="600" ry="600" fill={`url(#${id}_grad1)`} />
<ellipse cx="300" cy="0" rx="400" ry="400" fill={`url(#${id}_grad2)`} />
<ellipse cx="100" cy="550" rx="200" ry="200" fill={`url(#${id}_grad3)`} />
<ellipse cx="300" cy="450" rx="400" ry="400" fill={`url(#${id}_grad4)`} />
<ellipse cx="50" cy="250" rx="200" ry="200" fill={`url(#${id}_grad5)`} />
<ellipse cx="400" cy="220" rx="400" ry="400" fill={`url(#${id}_grad6)`} />
<ellipse cx="100" cy="290" rx="500" ry="500" fill={`url(#${id}_grad7)`} />

<ellipse
cx="250"
cy="250"
rx="500"
ry="500"
fill={`url(#${id}_grad1)`}
opacity={0.5}
/>
<ellipse
cx={400 + positions[0][0]}
cy={400 + positions[0][1]}
rx={350 + positions[0][2]}
ry={350 + positions[0][2]}
fill={`url(#${id}_grad1)`}
/>
<ellipse
cx={positions[1][0]}
cy={positions[1][1]}
rx={350 + positions[1][2]}
ry={350 + positions[1][2]}
fill={`url(#${id}_grad2)`}
/>
<ellipse
cx={400 + positions[2][0]}
cy={positions[2][1]}
rx={350 + positions[2][2]}
ry={350 + positions[2][2]}
fill={`url(#${id}_grad3)`}
/>
<ellipse
cx={positions[3][0]}
cy={positions[3][1]}
rx={100 + positions[3][2]}
ry={100 + positions[3][2]}
fill={`url(#${id}_grad2)`}
opacity={0.5}
/>
<ellipse
cx={positions[4][0]}
cy={positions[4][1]}
rx={100 + positions[4][2]}
ry={100 + positions[4][2]}
fill={`url(#${id}_grad3)`}
opacity={0.5}
/>

Check warning on line 131 in packages/thirdweb/src/react/web/ui/ConnectWallet/Blobbie.tsx

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/react/web/ui/ConnectWallet/Blobbie.tsx#L86-L131

Added lines #L86 - L131 were not covered by tests
</svg>
);
}

0 comments on commit cf4443a

Please sign in to comment.