Skip to content

Commit

Permalink
fix: body improvements (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
jpgonzalezra authored Jan 24, 2024
1 parent a91cb79 commit fee39cb
Show file tree
Hide file tree
Showing 6 changed files with 248 additions and 154 deletions.
20 changes: 16 additions & 4 deletions packages/contracts/src/LucidOrigins.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,16 @@ contract LucidOrigins is Owned, ERC721A, Background, Face, Body, Head, Blush {
string memory linesColor = isColorDark(r, g, b) ? "#FFF" : "#000";

string memory face = face(
normalizeToRange(dna[Constants.EYE_RADIUS_INDEX], 4, 7),
normalizeToRange(dna[Constants.EYE_RADIUS_INDEX], 7, 7),
normalizeToRange(dna[Constants.EYE_BROW_LENGHT_INDEX], 2, 4),
normalizeToRange(dna[Constants.EYE_SEPARATION_INDEX], 20, 30),
normalizeToRange(dna[Constants.EYE_SEPARATION_INDEX], 20, 25),
normalizeToRange(dna[Constants.EYE_BROW_ROTATION_INDEX], 0, 20),
normalizeToRange(dna[Constants.MOUNTH_ROTATION], 0, 6),
normalizeToRange(dna[Constants.EYE_BROW_SIZE_INDEX], 1, 5),
linesColor
linesColor,
r2,
g2,
b2
);

(string memory colorDefs, string memory fillColor) =
Expand All @@ -59,9 +62,18 @@ contract LucidOrigins is Owned, ERC721A, Background, Face, Body, Head, Blush {
fillColor
);

string memory body = body(
normalizeToRange(dna[Constants.HEAD_SIZE_INDEX], 95, 125),
normalizeToRange(dna[Constants.HEAD_SIZE_INDEX], 1, 3),
normalizeToRange(dna[Constants.HEAD_MIN_GROWTH_INDEX], 9, 12),
normalizeToRange(dna[Constants.HEAD_EDGES_NUM_INDEX], 10, 55),
colorDefs,
fillColor
);

string memory footer = "</svg>";

string memory svgContent = string(abi.encodePacked(body(colorDefs, fillColor), head, face, blush()));
string memory svgContent = string(abi.encodePacked(body, head, face, blush()));

uint256 rotation = normalizeToRange(dna[Constants.HEAD_SIZE_INDEX], 0, 3);
string memory svg = string(abi.encodePacked(header, background, rotationWrapper(rotation, svgContent), footer));
Expand Down
3 changes: 2 additions & 1 deletion packages/contracts/src/layers/Background.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ contract Background {

function background(uint256 dnaBgLayer) internal view returns (string memory) {
return
string(abi.encodePacked('<rect x="0" y="0" width="100" height="100" fill="', bgColors[dnaBgLayer], '"/>'));

string(abi.encodePacked('<defs><pattern id="star" fill="', bgColors[dnaBgLayer], '" viewBox="0,0,10,10" width="10%" height="10%"><polygon points="0,0 2,5 0,10 5,8 10,10 8,5 10,0 5,2" /></pattern></defs>','<rect x="0" y="0" width="100" height="100" fill="url(#star)"/>'));
}
}
136 changes: 136 additions & 0 deletions packages/contracts/src/layers/Blob.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// SPDX-License-Identifier: GNU GPLv3
pragma solidity 0.8.21;

// import { console2 } from "forge-std/console2.sol";
import { LibString } from "solmate/utils/LibString.sol";
import { Trigonometry } from "solidity-trigonometry/Trigonometry.sol";

contract Blob {
struct Point {
int256 x;
int256 y;
}

using LibString for int256;
using Trigonometry for uint256;

function createPoints(
uint256 size,
uint256 x,
uint256 y,
uint256 minGrowth,
uint256 edgesNum
)
internal
view
returns (Point[] memory)
{
Point[] memory points = new Point[](edgesNum);

uint256 outerRad = size / 2;
uint256 innerRad = minGrowth * (outerRad / 10);
uint256 deg = 360 / edgesNum;

for (uint256 i = 0; i < edgesNum; i++) {
uint256 degree = i * deg;
uint256 radius = randPoint(i, innerRad, outerRad);
Point memory point = calculatePoint(x, y, radius, degree);
points[i] = point;
}

return points;
}

function calculatePoint(
uint256 _x,
uint256 _y,
uint256 radius,
uint256 degree
)
internal
pure
returns (Point memory)
{
uint256 scaledDegree = degree * 1e18;
uint256 scaledPI = Trigonometry.PI;

int256 cosValue = uint256(scaledDegree * scaledPI / 180 / 1e18).cos();
int256 sinValue = (scaledDegree * scaledPI / 180 / 1e18).sin();

int256 x = int256(_x) + int256(radius) * cosValue / 1e18;
int256 y = int256(_y) + int256(radius) * sinValue / 1e18;

return Point(x, y);
}

function randPoint(uint256 i, uint256 minv, uint256 maxv) internal view returns (uint256) {
uint256 random = uint256(keccak256(abi.encodePacked(block.number, block.timestamp, i, minv, maxv))) % maxv;
return (random >= minv) ? random : minv + (random % (maxv - minv));
}

function createSvgPath(Point[] memory points) internal pure returns (string memory) {
string memory svgPath;
Point memory mid = Point({ x: (points[0].x + points[1].x) / 2, y: (points[0].y + points[1].y) / 2 });

svgPath = string(abi.encodePacked("M", mid.x.toString(), ",", mid.y.toString()));

for (uint256 i = 0; i < points.length; i++) {
Point memory p1 = points[(i + 1) % points.length];
Point memory p2 = points[(i + 2) % points.length];
Point memory midPoint = Point({ x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2 });

svgPath = string(
abi.encodePacked(
svgPath,
"Q",
p1.x.toString(),
",",
p1.y.toString(),
",",
midPoint.x.toString(),
",",
midPoint.y.toString()
)
);
}

return string(abi.encodePacked(svgPath, "Z"));
}

function build(
string memory id,
string memory colorDefs,
string memory fillColor,
string memory h1,
string memory h2
)
internal
pure
returns (string memory)
{
return string(
abi.encodePacked(
colorDefs,
'<path id="',
id,
'" d="',
h1,
'Z" stroke-width="2" stroke="black" transform-origin="center" fill="',
fillColor,
'">',
'<animate attributeName="d" values="',
h1,
";",
h2,
";",
h1,
'" dur="30s" id="body-anim" repeatCount="indefinite"',
' keysplines=".42 0 1 1; 0 0 .59 1; .42 0 1 1; 0 0 .59 1;',
' .42 0 1 1; 0 0 .59 1; .42 0 1 1; 0 0 .59 1;"/>',
'<animateTransform attributeName="transform" type="rotate" ',
'from="0" to="100" dur="1000" repeatCount="indefinite" />',
"</path>"
)
);
}
}
51 changes: 25 additions & 26 deletions packages/contracts/src/layers/Body.sol
Original file line number Diff line number Diff line change
@@ -1,34 +1,33 @@
// SPDX-License-Identifier: GNU GPLv3
pragma solidity 0.8.21;

contract Body {
function body(string memory colorDefs, string memory fillColor) internal pure returns (string memory) {
import { Blob } from "./Blob.sol";

contract Body is Blob {
function body(
uint256 size,
uint256 animation,
uint256 minGrowth,
uint256 edgesNum,
string memory colorDefs,
string memory fillColor
)
internal
view
returns (string memory)
{
uint256 x = 50;
uint256 y = 0;
string memory b1 = createSvgPath(createPoints(size, x, y, minGrowth, edgesNum));
string memory b2 = createSvgPath(createPoints(size + animation, x, y, minGrowth, edgesNum));

uint256 resize = size - 30;
string memory bi1 = createSvgPath(createPoints(resize, x, y, minGrowth - 2, edgesNum / 2));
string memory bi2 = createSvgPath(createPoints(resize + animation, x, y, minGrowth - 2, edgesNum / 2));

return string(
abi.encodePacked(
colorDefs,
'<path id="body" fill="',
fillColor,
'" stroke-width="2" stroke="black" stroke-linecap="round" d="M42.695 51.68C48.086',
"51.68 53.242 51.914 58.633 52.148 58.633 52.383 58.633 52.617 58.633 53.086 58.633 ",
"54.023 58.867 55.195 58.867 56.367 58.867 56.836 58.867 57.305 58.867 57.773 59.102 ",
"64.57 59.102 64.57 61.914 70.898 62.617 71.367 63.555 71.836 64.492 72.07 69.414 73.945 ",
"72.93 77.227 75.508 81.914 77.617 86.602 77.852 92.227 77.852 97.383 77.852 97.852 ",
"77.852 98.086 77.852 98.555 77.852 99.492 77.852 100.43 77.852 101.367 77.852 102.539 ",
"77.852 103.711 77.852 104.883 77.852 106.523 77.852 108.398 77.852 110.039 74.805 110.039 ",
"71.758 110.039 68.711 110.039 68.711 104.18 68.711 98.086 68.711 91.992 68.477 91.992 68.477 ",
"91.992 68.242 91.992 68.242 97.852 68.242 103.945 68.242 110.039 59.57 110.039 51.133 110.039 ",
"42.227 110.039 42.227 104.18 42.227 98.086 42.227 91.992 41.992 91.992 41.992 91.992 41.758 ",
"91.992 41.758 97.852 41.758 103.945 41.758 110.039 36.133 110.039 36.133 110.039 33.789 ",
"110.039 32.148 110.039 30.508 110.039 28.867 110.039 27.461 110.039 26.289 110.039 24.883 ",
"110.039 24.414 110.039 23.945 110.039 23.477 110.039 22.773 110.039 22.07 110.039 21.367 ",
"110.039 21.133 110.039 20.898 110.039 20.664 110.039 19.258 110.039 19.258 110.039 19.023 ",
"109.805 19.023 109.336 19.023 108.867 19.023 108.633 19.023 108.164 19.023 108.164 19.023 ",
"107.695 19.023 107.461 19.023 107.227 19.023 106.992 19.023 106.523 19.023 106.289 19.023 ",
"106.055 19.023 105.352 19.023 104.648 19.023 103.945 19.023 103.477 19.023 102.773 19.023 ",
"102.07 18.789 93.164 19.492 82.383 25.82 75.352 28.398 73.008 31.211 72.305 34.492 71.836 ",
"38.008 71.367 38.008 71.367 41.289 69.727 41.992 68.086 41.758 66.211 41.992 64.57 41.992 ",
"64.336 41.992 64.336 41.992 63.867 41.992 63.164 41.992 62.461 41.992 61.523 42.227 52.852 ",
'42.227 52.852 42.695 51.68Z"/>"'
build("body", colorDefs, fillColor, b1, b2), build("inner-body", colorDefs, fillColor, bi1, bi2)
)
);
}
Expand Down
71 changes: 62 additions & 9 deletions packages/contracts/src/layers/Face.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,75 @@ contract Face {
uint256 eyebrowRotation,
uint256 mouthRotation,
uint256 eyebrowSize,
string memory linesColor
string memory linesColor,
uint256 r,
uint256 g,
uint256 b
)
internal
pure
returns (string memory)
{
string memory eyes = getEyes(eyeRadius, eyeSeparation, eyebrowRotation, linesColor);
string memory eyebrows = getEyebrows(eyebrowLength, eyebrowRotation, eyebrowSize, mouthRotation, linesColor);
string memory mouth = getMouth(eyeSeparation, eyebrowRotation, eyebrowSize, mouthRotation, linesColor);
string memory eyes = getEyes(eyeRadius, eyeSeparation, mouthRotation, eyebrowRotation, r, g, b);
//string memory eyebrows = getEyebrows(eyebrowLength, eyebrowRotation, eyebrowSize, mouthRotation, linesColor);
//string memory mouth = getMouth(eyeSeparation, eyebrowRotation, eyebrowSize, mouthRotation, linesColor);

return string(
abi.encodePacked('<g id="face" transform="scale(0.6) translate(25 25)">', eyes, eyebrows, mouth, "</g>")
// abi.encodePacked('<g id="face" transform="scale(0.6) translate(30 30)">', eyes, eyebrows, mouth, "</g>")
abi.encodePacked('<g id="face" >', eyes, /*eyebrows, mouth,*/ "</g>")
);
}

function getEyes(
uint256 eyeRadius,
uint256 eyeSeparation,
uint256 pupilRadius,
uint256 pupilColor,
uint256 r,
uint256 g,
uint256 b
)
internal
pure
returns (string memory)
{
// string memory pupilAlternativeColor = string(abi.encodePacked("rgb(", r.toString(), ",", g.toString(), ",",
// b.toString(), ")"));
return string(
abi.encodePacked(
'<g id="face">',
'<circle cx="',
(50 - eyeSeparation / 2).toString(),
'" cy="40" r="',
eyeRadius.toString(),
'" fill="white"/>',
'<circle cx="',
(50 - eyeSeparation / 2).toString(),
'" cy="40" r="',
(pupilRadius < 3 ? 0 : pupilRadius).toString(),
'" fill="',
pupilColor > 15
? string(abi.encodePacked("rgb(", r.toString(), ",", g.toString(), ",", b.toString(), ")"))
: "black",
'"/>' '<circle cx="',
(50 + eyeSeparation / 2).toString(),
'" cy="40" r="',
eyeRadius.toString(),
'" fill="white"/>',
'<circle cx="',
(50 + eyeSeparation / 2).toString(),
'" cy="40" r="',
(pupilRadius < 3 ? 0 : pupilRadius).toString(),
'" fill="',
pupilColor > 15
? string(abi.encodePacked("rgb(", r.toString(), ",", g.toString(), ",", b.toString(), ")"))
: "black",
'"/>' "</g>"
)
);
}

function _getEyes(
uint256 eyeRadius,
uint256 eyeSeparation,
uint256 eyebrowRotation,
Expand All @@ -41,7 +94,7 @@ contract Face {
{
return string(
abi.encodePacked(
'<g id="face">',
'<g id="eyes">',
'<circle cx="',
(50 - eyeSeparation / 2).toString(),
'" cy="40" r="',
Expand Down Expand Up @@ -95,7 +148,7 @@ contract Face {
(30 - eyebrowLength).toString(),
'" stroke="',
linesColor,
'" stroke-width="4" stroke-linecap="round" transform="rotate(',
'" stroke-width="2" stroke-linecap="round" transform="rotate(',
eyebrowRotation.toString(),
" 35 ",
(30 - eyebrowLength).toString(),
Expand All @@ -112,7 +165,7 @@ contract Face {
(30 - eyebrowLength).toString(),
'" stroke="',
linesColor,
'" stroke-width="4" stroke-linecap="round" transform="rotate(',
'" stroke-width="2" stroke-linecap="round" transform="rotate(',
eyebrowRotation.toString(),
" 65 ",
(30 - eyebrowLength).toString(),
Expand Down Expand Up @@ -162,7 +215,7 @@ contract Face {
y3.toString(),
'" stroke="',
linesColor,
'" stroke-width="4" fill="transparent" stroke-linecap="round" transform="rotate(',
'" stroke-width="2" fill="transparent" stroke-linecap="round" transform="rotate(',
mouthRotation.toString(),
" 50 ",
(50 + controlY).toString(),
Expand Down
Loading

0 comments on commit fee39cb

Please sign in to comment.