let cp2y = y - 134.8 * scaleY
x += 130.5 * scaleX
y -= 193.7 * scaleY
g.bezierVertex(cp1x, cp1y, cp2x, cp2y, x, y)
cp1x = x + 64.9 * scaleX
cp1y = y - 76.8 * scaleY
cp2x = x + 78.7 * scaleX
cp2y = y - 250.3 * scaleY
x += 100.8 * scaleX
y -= 385.7 * scaleY
g.bezierVertex(cp1x, cp1y, cp2x, cp2y, x, y)
cp1x = x + 17.8 * scaleX
cp1y = y - 109.2 * scaleY
cp2x = x + 134.3 * scaleX
cp2y = y - 225.2 * scaleY
x += 272.5 * scaleX
y -= 225.3 * scaleY
g.bezierVertex(cp1x, cp1y, cp2x, cp2y, x, y)
cp1x = 2 * x - cp2x
cp1y = 2 * y - cp2y
cp2x = x + 244.5 * scaleX
cp2y = y + 116 * scaleY
x += 263.8 * scaleX
y += 265.3 * scaleY
g.bezierVertex(cp1x, cp1y, cp2x, cp2y, x, y)
cp1x = x + 42.3 * scaleX
cp1y = y + 274.2 * scaleY
cp2x = x + 91.2 * scaleX
cp2y = y + 343 * scaleY
x += 91.2 * scaleX
y += 343 * scaleY
g.bezierVertex(cp1x, cp1y, cp2x, cp2y, x, y)
cp1x = x + 56.5 * scaleX
cp1y = y + 79.5 * scaleY
cp2x = x + 143.4 * scaleX
cp2y = y + 199.4 * scaleY
x += 143.4 * scaleX
y += 199.4 * scaleY
g.bezierVertex(cp1x, cp1y, cp2x, cp2y, x, y)
y += 115.4 * scaleY
g.vertex(x, y)
cp1x = x + 0 * scaleX
cp1y = y + 0 * scaleY
cp2x = x - 1000.9 * scaleX
cp2y = y + 2.7 * scaleY
x -= 1000.9 * scaleX
y += 2.7 * scaleY
g.bezierVertex(cp1x, cp1y, cp2x, cp2y, x, y)
x -= 1.2 * scaleX
y -= 120.9 * scaleY
g.vertex(x, y)
g.endShape(CLOSE)
}
function drawDuxArchetype(g, scaleX, scaleY) {
g.beginShape()
g.vertex(531.5 * scaleX, 60.4 * scaleY)
g.vertex(500.1 * scaleX, 10.9 * scaleY)
g.vertex(472.5 * scaleX, 61.4 * scaleY)
g.vertex(502.9 * scaleX, 88 * scaleY)
g.endShape(CLOSE)
g.beginShape()
g.vertex(854.6 * scaleX, 792.0 * scaleY)
g.vertex(748.3 * scaleX, 660.7 * scaleY)
g.vertex(765.0 * scaleX, 506.9 * scaleY)
g.vertex(841.7 * scaleX, 493.9 * scaleY)
g.vertex(841.0 * scaleX, 492.7 * scaleY)
g.vertex(849.8 * scaleX, 364.1 * scaleY)
g.vertex(800.7 * scaleX, 423.5 * scaleY)
g.vertex(768.8 * scaleX, 368.6 * scaleY)
g.vertex(886.0 * scaleX, 238.3 * scaleY)
g.vertex(859.1 * scaleX, 103.2 * scaleY)
g.vertex(805.6 * scaleX, 202.7 * scaleY)
g.vertex(560.1 * scaleX, 91.5 * scaleY)
g.vertex(504.5 * scaleX, 111.0 * scaleY)
g.vertex(440.9 * scaleX, 91.5 * scaleY)
g.vertex(214.2 * scaleX, 190.9 * scaleY)
g.vertex(145.1 * scaleX, 101.5 * scaleY)
g.vertex(130.9 * scaleX, 232.4 * scaleY)
g.vertex(239.3 * scaleX, 363.3 * scaleY)
g.vertex(214.6 * scaleX, 411.3 * scaleY)
g.vertex(161.5 * scaleX, 353.0 * scaleY)
g.vertex(165.4 * scaleX, 506.8 * scaleY)
g.vertex(164.1 * scaleX, 509.4 * scaleY)
g.vertex(239.7 * scaleX, 516.1 * scaleY)
g.vertex(261.4 * scaleX, 661.0 * scaleY)
g.vertex(157.7 * scaleX, 794.8 * scaleY)
g.vertex(-0.8 * scaleX, 825.7 * scaleY)
g.vertex(0.0 * scaleX, 999.8 * scaleY)
g.vertex(1000.3 * scaleX, 1000.0 * scaleY)
g.vertex(1000.3 * scaleX, 820.2 * scaleY)
g.endShape(CLOSE)
}
function drawBulwarkArchetype(g, scaleX, scaleY) {
g.beginShape()
g.vertex(958.3 * scaleX, 833.3 * scaleY)
g.vertex(916.6 * scaleX, 795.8 * scaleY)
g.vertex(962.3 * scaleX, 696.3 * scaleY)
g.vertex(857.8 * scaleX, 742.9 * scaleY)
g.vertex(838.9 * scaleX, 725.8 * scaleY)
g.vertex(870.4 * scaleX, 657.3 * scaleY)
g.vertex(798.4 * scaleX, 689.4 * scaleY)
g.vertex(762.8 * scaleX, 657.3 * scaleY)
g.vertex(801.8 * scaleX, 557.6 * scaleY)
g.vertex(762.8 * scaleX, 512.4 * scaleY)
g.vertex(826.2 * scaleX, 384.2 * scaleY)
g.vertex(762.8 * scaleX, 326.4 * scaleY)
g.vertex(852.5 * scaleX, 175.7 * scaleY)
g.vertex(752.8 * scaleX, 102.5 * scaleY)
g.vertex(253.8 * scaleX, 102.5 * scaleY)
g.vertex(154.7 * scaleX, 175.7 * scaleY)
g.vertex(243.8 * scaleX, 326.4 * scaleY)
g.vertex(182.6 * scaleX, 384.2 * scaleY)
g.vertex(243.8 * scaleX, 518.2 * scaleY)
g.vertex(208.7 * scaleX, 557.6 * scaleY)
g.vertex(243.8 * scaleX, 657.7 * scaleY)
g.vertex(193.9 * scaleX, 704.4 * scaleY)
g.vertex(132.8 * scaleX, 676.3 * scaleY)
g.vertex(159.6 * scaleX, 736.5 * scaleY)
g.vertex(144.5 * scaleX, 750.5 * scaleY)
g.vertex(43.6 * scaleX, 704.2 * scaleY)
g.vertex(87.9 * scaleX, 803.5 * scaleY)
g.vertex(39 * scaleX, 849.3 * scaleY)
g.vertex(0.1 * scaleX, 858.4 * scaleY)
g.vertex(-1.2 * scaleX, 1001.1 * scaleY)
g.vertex(1000.3 * scaleX, 1001.4 * scaleY)
g.vertex(1000.4 * scaleX, 846.4 * scaleY)
g.endShape(CLOSE)
}
function drawWardenArchetype(g, scaleX, scaleY) {
g.beginShape()
g.vertex(960 * scaleX, 662.3 * scaleY)
g.vertex(960.8 * scaleX, 661.7 * scaleY)
g.vertex(958.3 * scaleX, 661.7 * scaleY)
g.vertex(909.1 * scaleX, 510 * scaleY)
g.vertex(880.7 * scaleX, 654.7 * scaleY)
g.vertex(859 * scaleX, 587.7 * scaleY)
g.vertex(835.7 * scaleX, 659.4 * scaleY)
g.vertex(790.1 * scaleX, 622 * scaleY)
g.vertex(762.8 * scaleX, 528.5 * scaleY)
g.vertex(776.2 * scaleX, 384.2 * scaleY)
g.vertex(762.8 * scaleX, 326.4 * scaleY)
g.vertex(742.5 * scaleX, 175.7 * scaleY)
g.vertex(642.8 * scaleX, 102.5 * scaleY)
g.vertex(363.8 * scaleX, 102.5 * scaleY)
g.vertex(264.7 * scaleX, 175.7 * scaleY)
g.vertex(243.8 * scaleX, 326.4 * scaleY)
g.vertex(232.6 * scaleX, 384.2 * scaleY)
g.vertex(243.8 * scaleX, 528.5 * scaleY)
g.vertex(219.8 * scaleX, 622 * scaleY)
g.vertex(178.4 * scaleX, 660.9 * scaleY)
g.vertex(177.8 * scaleX, 660.9 * scaleY)
g.vertex(155.2 * scaleX, 591.5 * scaleY)
g.vertex(132.4 * scaleX, 661.8 * scaleY)
g.vertex(131.6 * scaleX, 661.9 * scaleY)
g.vertex(87.8 * scaleX, 510 * scaleY)
g.vertex(51.7 * scaleX, 661.9 * scaleY)
g.vertex(0.1 * scaleX, 673.5 * scaleY)
g.vertex(-1.2 * scaleX, 1001.1 * scaleY)
g.vertex(1000.3 * scaleX, 1001.4 * scaleY)
g.vertex(1000.7 * scaleX, 673.5 * scaleY)
g.endShape(CLOSE)
}
function drawShadeArchetype(g, scaleX, scaleY) {
g.beginShape()
g.vertex(909 * scaleX, 623.5 * scaleY)
g.vertex(844 * scaleX, 651.3 * scaleY)
g.vertex(707.2 * scaleX, 181.5 * scaleY)
g.vertex(546.4 * scaleX, 106.5 * scaleY)
g.vertex(509.6 * scaleX, 69.7 * scaleY)
g.vertex(474.1 * scaleX, 105.2 * scaleY)
g.vertex(309.5 * scaleX, 179.3 * scaleY)
g.vertex(184.8 * scaleX, 651.3 * scaleY)
g.vertex(124 * scaleX, 623.5 * scaleY)
g.vertex(0.3 * scaleX, 988.8 * scaleY)
g.vertex(0.5 * scaleX, 1003 * scaleY)
g.vertex(1000 * scaleX, 1002.6 * scaleY)
g.vertex(1001.2 * scaleX, 987.1 * scaleY)
g.endShape(CLOSE)
}
function drawBruteArchetype(g, scaleX, scaleY) {
g.beginShape()
// Starting point
g.vertex(940.1 * scaleX, 779.9 * scaleY)
// l21.8-23.7 -> 961.9, 756.2
g.vertex(961.9 * scaleX, 756.2 * scaleY)
// l-49.4,17.8 -> 912.5, 774
g.vertex(912.5 * scaleX, 774 * scaleY)
// l-27.7-5.9 -> 884.8, 768.1
g.vertex(884.8 * scaleX, 768.1 * scaleY)
// l29.2-44.7 -> 914, 723.4
g.vertex(914 * scaleX, 723.4 * scaleY)
// l-92,31.3 -> 822, 754.7
g.vertex(822 * scaleX, 754.7 * scaleY)
// l-12-2.6 -> 810, 752.1
g.vertex(810 * scaleX, 752.1 * scaleY)
// l76.6-74 -> 886.6, 678.1
g.vertex(886.6 * scaleX, 678.1 * scaleY)
// l-138.5,68.6 -> 748.1, 746.7
g.vertex(748.1 * scaleX, 746.7 * scaleY)
// h.1 (tiny horizontal)
g.vertex(748.2 * scaleX, 746.7 * scaleY)
// c0,0-77.4,37.6-77.4,37.6 -> 670.8, 784.3
g.vertex(670.8 * scaleX, 784.3 * scaleY)
// l41.5-73.4 -> 712.3, 710.9
g.vertex(712.3 * scaleX, 710.9 * scaleY)
// l45.1-426.7 -> 757.4, 284.2
g.vertex(757.4 * scaleX, 284.2 * scaleY)
// c77,23.1,137.3,227.8,137.3,149 (curve to 894.7, 433.2 but end at 894.7, 284.2)
g.bezierVertex(834.4 * scaleX, 307.3 * scaleY, 894.7 * scaleX, 512 * scaleY, 894.7 * scaleX, 433.2 * scaleY)
// c0-58.3-24.2-142.6-61.6-200.8 -> 833.1, 232.4
g.bezierVertex(894.7 * scaleX, 374.9 * scaleY, 870.5 * scaleX, 290.6 * scaleY, 833.1 * scaleX, 232.4 * scaleY)
// c.6,0,1.1,0,1.7,0 -> 834.8, 232.4
g.vertex(834.8 * scaleX, 232.4 * scaleY)
// c59.1,0,107.1-84.6,107.1-189.5 -> 941.9, 42.9
g.bezierVertex(893.9 * scaleX, 232.4 * scaleY, 941.9 * scaleX, 147.8 * scaleY, 941.9 * scaleX, 42.9 * scaleY)
// s-37.6,72-87.3,101.1 (smooth curve) -> 854.6, 144
g.bezierVertex(941.9 * scaleX, 114.9 * scaleY, 904.3 * scaleX, 144 * scaleY, 854.6 * scaleX, 144 * scaleY)
// l-219.5-27.7 -> 635.1, 116.3
g.vertex(635.1 * scaleX, 116.3 * scaleY)
// l-274.6-.2 -> 360.5, 116.1
g.vertex(360.5 * scaleX, 116.1 * scaleY)
// l-195.3,31.1 -> 165.2, 147.2
g.vertex(165.2 * scaleX, 147.2 * scaleY)
// C112.4,126,71.5-11.5,71.5,43.1 (absolute curve)
g.bezierVertex(112.4 * scaleX, 126 * scaleY, 71.5 * scaleX, -11.5 * scaleY, 71.5 * scaleX, 43.1 * scaleY)
// s35.4,156.6,82.9,182.8 -> 154.4, 225.9
g.bezierVertex(71.5 * scaleX, 97.7 * scaleY, 106.9 * scaleX, 199.7 * scaleY, 154.4 * scaleX, 225.9 * scaleY)
// c-38.2,48.5-63.1,127.7-63.1,217.5 -> 91.3, 443.4
g.bezierVertex(116.2 * scaleX, 274.4 * scaleY, 91.3 * scaleX, 353.6 * scaleY, 91.3 * scaleX, 443.4 * scaleY)
// c0,83.5,67.7-151.1,151.1-151.1 -> 242.4, 292.3
g.bezierVertex(91.3 * scaleX, 526.9 * scaleY, 159 * scaleX, 292.3 * scaleY, 242.4 * scaleX, 292.3 * scaleY)
// c3.3,0,6.6-.2,9.9-.6 -> 252.3, 291.7
g.vertex(252.3 * scaleX, 291.7 * scaleY)
// l.4.6 -> 252.7, 292.3
g.vertex(252.7 * scaleX, 292.3 * scaleY)
// l49.9,418.8 -> 302.6, 711.1
g.vertex(302.6 * scaleX, 711.1 * scaleY)
// l40.7,75 -> 343.3, 786.1
g.vertex(343.3 * scaleX, 786.1 * scaleY)
// l-123.5-52.2 -> 219.8, 733.9
g.vertex(219.8 * scaleX, 733.9 * scaleY)
// l-126.3-68.6 -> 93.5, 665.3
g.vertex(93.5 * scaleX, 665.3 * scaleY)
// l72.4,76.7 -> 165.9, 742
g.vertex(165.9 * scaleX, 742 * scaleY)
// l-9.3,1.4 -> 156.6, 743.4
g.vertex(156.6 * scaleX, 743.4 * scaleY)
// l-88.1-32.9 -> 68.5, 710.5
g.vertex(68.5 * scaleX, 710.5 * scaleY)
// l25.2,42.3 -> 93.7, 752.8
g.vertex(93.7 * scaleX, 752.8 * scaleY)
// l-32.5,4.9 -> 61.2, 757.7
g.vertex(61.2 * scaleX, 757.7 * scaleY)
// l-36.4-14.4 -> 24.8, 743.3
g.vertex(24.8 * scaleX, 743.3 * scaleY)
// l14.8,17.6 -> 39.6, 760.9
g.vertex(39.6 * scaleX, 760.9 * scaleY)
// l-42.9,6.4 -> -3.3, 767.3 (clamp to 0)
g.vertex(0 * scaleX, 767.3 * scaleY)
// l1.6,231.7 -> 1.6, 999
g.vertex(1.6 * scaleX, 999 * scaleY)
// h1001.1 -> 1002.7, 999
g.vertex(1002.7 * scaleX, 999 * scaleY)
// v-206.5 -> 1002.7, 792.5
g.vertex(1002.7 * scaleX, 792.5 * scaleY)
// l-59.4-12.7 -> 943.3, 779.8 (close to start)
g.vertex(943.3 * scaleX, 779.8 * scaleY)
g.endShape(CLOSE)
}
function drawEmperorArchetype(g, scaleX, scaleY) {
// New Emperor form from updated SVG
g.beginShape()
// Start at 936.5, 608.1
g.vertex(936.5 * scaleX, 608.1 * scaleY)
// Line to (936.5-142.7, 608.1-77.7) = (793.8, 530.4)
g.vertex(793.8 * scaleX, 530.4 * scaleY)
// The path continues with curves, but we'll approximate with vertices
// c.5-2.5.8-5 .8-7.7 (relative curve, small adjustment)
g.vertex(794.6 * scaleX, 522.7 * scaleY)
// c0-10.8-4.9-20.5-12.5-27
g.vertex(782.1 * scaleX, 495.7 * scaleY)
// l73.7-316.8 (line to relative)
g.vertex(855.8 * scaleX, 178.9 * scaleY)
// s-133.6-106.3-171.4-106 (smooth curve approximated)
g.vertex(684.4 * scaleX, 72.9 * scaleY)
// c-4.7-.7-5.6,7.6-3.8,9.5 (small curve)
g.vertex(680.6 * scaleX, 82.4 * scaleY)
// l61.5,65.5
g.vertex(742.1 * scaleX, 147.9 * scaleY)
// l-17.4,7.6
g.vertex(724.7 * scaleX, 155.5 * scaleY)
// c-18.2-4.2-42.9-7.7-71.7-10.6
g.vertex(653.0 * scaleX, 144.9 * scaleY)
// l13.7-34.7
g.vertex(666.7 * scaleX, 110.2 * scaleY)
// c-.6-3.2-3.3-5-6.3-4 (small adjustment)
g.vertex(660.4 * scaleX, 106.2 * scaleY)
// c-1.4.4-14.9,17.1-17.2,19.9
g.vertex(643.2 * scaleX, 126.1 * scaleY)
// c-4.6,5.5-9.1,11.1-13.6,16.7
g.vertex(629.6 * scaleX, 142.8 * scaleY)
// c-16-1.3-33-2.3-50.5-3.2
g.vertex(579.1 * scaleX, 139.6 * scaleY)
// l32.7-82.7
g.vertex(611.8 * scaleX, 56.9 * scaleY)
// c-.6-3.2-3.3-5-6.3-4
g.vertex(605.5 * scaleX, 52.9 * scaleY)
// c-1.4.4-14.9,17.1-17.2,19.9
g.vertex(588.3 * scaleX, 72.8 * scaleY)
// c-17.7,21.5-35.1,43.3-52.4,65.2
g.vertex(535.9 * scaleX, 138.0 * scaleY)
// c-7.7-.2-15.4-.4-23.1-.5
g.vertex(512.8 * scaleX, 137.5 * scaleY)
// l-13.5-38.5
g.vertex(499.3 * scaleX, 99.0 * scaleY)
// c-1.4-4.1-7.3-4.1-8.6,0
g.vertex(490.7 * scaleX, 99.0 * scaleY)
// l-12.6,38.2
g.vertex(478.1 * scaleX, 137.2 * scaleY)
// c-7.6,0-15.1,0-22.6.2
g.vertex(455.5 * scaleX, 137.4 * scaleY)
// c-20.8-22.1-41.5-44.3-62.6-66
g.vertex(392.9 * scaleX, 71.4 * scaleY)
// c-2.6-2.7-17.7-18.4-19.2-18.8
g.vertex(373.7 * scaleX, 52.6 * scaleY)
// c-3.3-.8-5.9,1.2-6.4,4.4
g.vertex(367.3 * scaleX, 57.0 * scaleY)
// l39.7,81.8
g.vertex(407.0 * scaleX, 138.8 * scaleY)
// c-19.1.8-37.5,2-54.6,3.5
g.vertex(352.4 * scaleX, 142.3 * scaleY)
// c-4.6-4.8-9.1-9.5-13.7-14.2
g.vertex(338.7 * scaleX, 128.1 * scaleY)
// c-2.6-2.7-17.7-18.4-19.2-18.8
g.vertex(319.5 * scaleX, 109.3 * scaleY)
// c-3.3-.8-5.9,1.2-6.4,4.4
g.vertex(313.1 * scaleX, 113.7 * scaleY)
// l15.2,31.2
g.vertex(328.3 * scaleX, 144.9 * scaleY)
// c-22.5,2.7-41.9,6.2-56.7,10.5
g.vertex(271.6 * scaleX, 155.4 * scaleY)
// l-16.9-7.5
g.vertex(254.7 * scaleX, 147.9 * scaleY)
// l61.6-65.4
g.vertex(316.3 * scaleX, 82.5 * scaleY)
// c1.8-1.9,1-10.2-3.7-9.5
g.vertex(312.6 * scaleX, 73.0 * scaleY)
// c-78.6,24.3-171.4,105.7-171.4,105.7
g.vertex(141.2 * scaleX, 178.7 * scaleY)
// l72.3,302.4
g.vertex(213.5 * scaleX, 481.1 * scaleY)
// c-8.3,6.5-13.6,16.5-13.6,27.9
g.vertex(199.9 * scaleX, 509.0 * scaleY)
// s.9,8.9,2.4,12.9
g.vertex(202.3 * scaleX, 521.9 * scaleY)
// l-143.1,82.9
g.vertex(59.2 * scaleX, 604.8 * scaleY)
// L-.7,834.6 (absolute line)
g.vertex(-0.7 * scaleX, 834.6 * scaleY)
// l1.6,166.5
g.vertex(0.9 * scaleX, 1001.1 * scaleY)
// h1001.1 (horizontal line)
g.vertex(1002.0 * scaleX, 1001.1 * scaleY)
// v-172.3 (vertical line up)
g.vertex(1002.0 * scaleX, 828.8 * scaleY)
// l-65.5-220.7
g.vertex(936.5 * scaleX, 608.1 * scaleY)
g.endShape(CLOSE)
}
function drawArmatusArchetype(g, scaleX, scaleY) {
// Armatus form - angular armor-like silhouette with crown spikes
g.beginShape()
// Start at right side: 817.9, 763.3
g.vertex(817.9 * scaleX, 763.3 * scaleY)
// l-130.2-633.3 (diagonal line up-left to shoulder)
g.vertex(687.7 * scaleX, 130.0 * scaleY)
// v-51.2 (vertical line up)
g.vertex(687.7 * scaleX, 78.8 * scaleY)
// l-22.2-10 (crown spike 1)
g.vertex(665.5 * scaleX, 68.8 * scaleY)
// v53.8
g.vertex(665.5 * scaleX, 122.6 * scaleY)
// c-5.2-1.4-10.7-2.7-16.6-3.9
g.vertex(648.9 * scaleX, 118.7 * scaleY)
// v-31.3
g.vertex(648.9 * scaleX, 87.4 * scaleY)
// l-22.2-10 (crown spike 2)
g.vertex(626.7 * scaleX, 77.4 * scaleY)
// v37.3
g.vertex(626.7 * scaleX, 114.7 * scaleY)
// c-5.4-.8-10.9-1.6-16.6-2.4
g.vertex(610.1 * scaleX, 112.3 * scaleY)
// v-15
g.vertex(610.1 * scaleX, 97.3 * scaleY)
// l-22.2-10 (crown spike 3)
g.vertex(587.9 * scaleX, 87.3 * scaleY)
// v22.5
g.vertex(587.9 * scaleX, 109.8 * scaleY)
// c-5.4-.5-10.8-1-16.3-1.5
g.vertex(571.6 * scaleX, 108.3 * scaleY)
// v-11
g.vertex(571.6 * scaleX, 97.3 * scaleY)
// l-22.9-10 (crown spike 4)
g.vertex(548.7 * scaleX, 87.3 * scaleY)
// v19.5
g.vertex(548.7 * scaleX, 106.8 * scaleY)
// c-5.4-.3-10.8-.6-16.2-.8
g.vertex(532.5 * scaleX, 106.0 * scaleY)
// v-8.7
g.vertex(532.5 * scaleX, 97.3 * scaleY)
// l-22.2-10 (crown spike 5)
g.vertex(510.3 * scaleX, 87.3 * scaleY)
// v18.1
g.vertex(510.3 * scaleX, 105.4 * scaleY)
// c-5.5,0-11.1-.2-16.6-.2
g.vertex(493.7 * scaleX, 105.2 * scaleY)
// v-17.9
g.vertex(493.7 * scaleX, 87.3 * scaleY)
// l-22.1,10 (crown spike 6 - going back up)
g.vertex(471.6 * scaleX, 97.3 * scaleY)
// v8.1
g.vertex(471.6 * scaleX, 105.4 * scaleY)
// c-5.6.1-11.2.3-16.7.5
g.vertex(454.9 * scaleX, 105.9 * scaleY)
// v-18.6
g.vertex(454.9 * scaleX, 87.3 * scaleY)
// l-21.8,10 (crown spike 7)
g.vertex(433.1 * scaleX, 97.3 * scaleY)
// v9.8
g.vertex(433.1 * scaleX, 107.1 * scaleY)
// c-5.8.4-11.5.8-17,1.3
g.vertex(416.1 * scaleX, 108.4 * scaleY)
// v-21.1
g.vertex(416.1 * scaleX, 87.3 * scaleY)
// l-22.2,10 (crown spike 8)
g.vertex(393.9 * scaleX, 97.3 * scaleY)
// v13.5
g.vertex(393.9 * scaleX, 110.8 * scaleY)
// c-5.7.7-11.3,1.6-16.6,2.5
g.vertex(377.3 * scaleX, 113.3 * scaleY)
// v-36
g.vertex(377.3 * scaleX, 77.3 * scaleY)
// l-22.2,10 (crown spike 9)
g.vertex(355.1 * scaleX, 87.3 * scaleY)
// v30.4
g.vertex(355.1 * scaleX, 117.7 * scaleY)
// c-5.9,1.4-11.5,2.9-16.6,4.6
g.vertex(338.5 * scaleX, 122.3 * scaleY)
// v-53.6
g.vertex(338.5 * scaleX, 68.7 * scaleY)
// l-22.2,10 (crown spike 10)
g.vertex(316.3 * scaleX, 78.7 * scaleY)
// v62.9
g.vertex(316.3 * scaleX, 141.6 * scaleY)
// l-157.9,618.3 (diagonal line down-left to bottom left)
g.vertex(158.4 * scaleX, 759.9 * scaleY)
// L-1.3,969.7 (line to bottom left corner area)
g.vertex(-1.3 * scaleX, 969.7 * scaleY)
// l1.6,29.3
g.vertex(0.3 * scaleX, 999.0 * scaleY)
// h1001.1 (horizontal line across bottom)
g.vertex(1001.4 * scaleX, 999.0 * scaleY)
// v-30.1
g.vertex(1001.4 * scaleX, 968.9 * scaleY)
// l-183.5-205.6 (diagonal line back to start)
g.vertex(817.9 * scaleX, 763.3 * scaleY)
g.endShape(CLOSE)
}
function drawTitanArchetype(g, scaleX, scaleY, maskCount) {
g.beginShape()
if (maskCount === "Conflux") {
let x = 1000.2 * scaleX
let y = 776.4 * scaleY
g.vertex(x, y)
let cp1x = x - 22.5 * scaleX
let cp1y = y - 31.3 * scaleY
let cp2x = x - 45.3 * scaleX
let cp2y = y - 63.4 * scaleY
x -= 65.5 * scaleX
y -= 91.7 * scaleY
g.bezierVertex(cp1x, cp1y, cp2x, cp2y, x, y)
cp1x = x - 48.9 * scaleX
cp1y = y - 68.7 * scaleY
cp2x = x - 71.9 * scaleX
cp2y = y - 193.7 * scaleY
x -= 91.2 * scaleX
y -= 343 * scaleY
g.bezierVertex(cp1x, cp1y, cp2x, cp2y, x, y)
cp1x = x - 19.3 * scaleX
cp1y = y - 149.2 * scaleY
cp2x = x - 176.1 * scaleX
cp2y = y - 274.1 * scaleY
x -= 360.8 * scaleX
y -= 274.1 * scaleY
g.bezierVertex(cp1x, cp1y, cp2x, cp2y, x, y)
cp1x = 2 * x - cp2x
cp1y = 2 * y - cp2y
cp2x = x - 314.1 * scaleX
cp2y = y + 124.9 * scaleY
x -= 332 * scaleX
y += 234.2 * scaleY
g.bezierVertex(cp1x, cp1y, cp2x, cp2y, x, y)
cp1x = x - 22.1 * scaleX
cp1y = y + 135.4 * scaleY
cp2x = x - 35.9 * scaleX
cp2y = y + 308.9 * scaleY
x -= 100.8 * scaleX
y += 385.7 * scaleY
g.bezierVertex(cp1x, cp1y, cp2x, cp2y, x, y)
cp1x = 32 * scaleX
cp1y = 708.7 * scaleY
cp2x = 16.7 * scaleX
cp2y = 728.9 * scaleY
x = 0 * scaleX
y = 751.7 * scaleY
g.bezierVertex(cp1x, cp1y, cp2x, cp2y, x, y)
x -= 0.2 * scaleX
y += 248.5 * scaleY
g.vertex(x, y)
x += 1000.2 * scaleX
y -= 0.3 * scaleY
g.vertex(x, y)
x += 0.3 * scaleX
y -= 223.5 * scaleY
g.vertex(x, y)
} else {
let x = -2.3 * scaleX
let y = 881.6 * scaleY
g.vertex(x, y)
let cp1x = x + 34.5 * scaleX
let cp1y = y - 70 * scaleY
let cp2x = x + 80.7 * scaleX
let cp2y = y - 134.8 * scaleY
x += 130.5 * scaleX
y -= 193.7 * scaleY
g.bezierVertex(cp1x, cp1y, cp2x, cp2y, x, y)
cp1x = x + 64.9 * scaleX
cp1y = y - 76.8 * scaleY
cp2x = x + 78.7 * scaleX
cp2y = y - 250.3 * scaleY
x += 100.8 * scaleX
y -= 385.7 * scaleY
g.bezierVertex(cp1x, cp1y, cp2x, cp2y, x, y)
cp1x = x + 17.8 * scaleX
cp1y = y - 109.2 * scaleY
cp2x = x + 134.3 * scaleX
cp2y = y - 225.2 * scaleY
x += 272.5 * scaleX
y -= 225.3 * scaleY
g.bezierVertex(cp1x, cp1y, cp2x, cp2y, x, y)
cp1x = 2 * x - cp2x
cp1y = 2 * y - cp2y
cp2x = x + 244.5 * scaleX
cp2y = y + 116 * scaleY
x += 263.8 * scaleX
y += 265.3 * scaleY
g.bezierVertex(cp1x, cp1y, cp2x, cp2y, x, y)
cp1x = x + 42.3 * scaleX
cp1y = y + 274.2 * scaleY
cp2x = x + 91.2 * scaleX
cp2y = y + 343 * scaleY
x += 91.2 * scaleX
y += 343 * scaleY
g.bezierVertex(cp1x, cp1y, cp2x, cp2y, x, y)
cp1x = x + 56.5 * scaleX
cp1y = y + 79.5 * scaleY
cp2x = x + 143.4 * scaleX
cp2y = y + 199.4 * scaleY
x += 143.4 * scaleX
y += 199.4 * scaleY
g.bezierVertex(cp1x, cp1y, cp2x, cp2y, x, y)
y += 115.4 * scaleY
g.vertex(x, y)
cp1x = x + 0 * scaleX
cp1y = y + 0 * scaleY
cp2x = x - 1000.9 * scaleX
cp2y = y + 2.7 * scaleY
x -= 1000.9 * scaleX
y += 2.7 * scaleY
g.bezierVertex(cp1x, cp1y, cp2x, cp2y, x, y)
x -= 1.2 * scaleX
y -= 120.9 * scaleY
g.vertex(x, y)
}
g.endShape(CLOSE)
}
/* ========================= MASK LAYOUT ========================= */
function layoutMasks() {
const count = TRAITS.count
const HEAD_ZONE_H = width // head zone is a square region at top, width x width
const cx = width / 2, cy = HEAD_ZONE_H / 2 // v2: center in head zone, not full canvas
const baseW = width * 0.62
const baseH = baseW * 1.18
if (count === "Mono") {
masks.push(makeMask(cx, cy, baseW, baseH, 0, 0))
} else if (count === "Conflux") {
const maskWidth = baseW * 0.86
const gap = maskWidth * 0.36
masks.push(makeMask(cx - gap / 2, cy, maskWidth, baseH * 0.86, -0.03, 0))
masks.push(makeMask(cx + gap / 2, cy, maskWidth, baseH * 0.86, 0.03, 1))
}
}
function makeMask(x, y, w, h, rot, maskIndex) {
return {
x, y, w, h, rot, maskIndex,
edgeStyle: TRAITS.edgeStyle,
sight: TRAITS.sight,
voice: TRAITS.voice,
scent: TRAITS.scent,
ornament: TRAITS.ornament,
hollows: TRAITS.hollows,
}
}
function drawMaskEyesBlocking(pg, m) {
pg.push()
pg.translate(m.x, m.y)
pg.rotate(PARAMS.axisLock ? 0 : m.rot)
const rx = m.w * 0.22
const ry = m.h * 0.13
const ly = -m.h * 0.12
const left = { x: -m.w * 0.18, y: ly }
const right = { x: m.w * 0.18, y: ly }
pg.noStroke()
pg.fill(0, 0, 10)
if (TRAITS.iris === "Null" || TRAITS.iris === "Fury" || TRAITS.iris === "Plasma" || TRAITS.iris === "Omnia") {
const strokeW = m.w * 0.03
if (m.sight === "Mono") {
const center = { x: 0, y: ly }
drawEye(pg, center, rx, ry, m.sight, strokeW)
} else if (m.sight === "Verge") {
drawVerticalAlmondTotal(pg, rx, ry, ly, m.w, strokeW)
} else {
drawEye(pg, left, rx, ry, m.sight, strokeW)
drawEye(pg, right, rx, ry, m.sight, strokeW)
}
} else if (TRAITS.iris === "Abyss") {
if (m.sight === "Mono") {
const center = { x: 0, y: ly }
drawEye(pg, center, rx, ry, m.sight, 0)
} else if (m.sight === "Verge") {
drawVerticalAlmondTotal(pg, rx, ry, ly, m.w, 0)
} else {
drawEye(pg, left, rx, ry, m.sight, 0)
drawEye(pg, right, rx, ry, m.sight, 0)
}
}
pg.pop()
}
function drawMaskEyes(pg, m) {
pg.push()
pg.translate(m.x, m.y)
pg.rotate(PARAMS.axisLock ? 0 : m.rot)
const rx = m.w * 0.22
const ry = m.h * 0.13
const ly = -m.h * 0.12
const left = { x: -m.w * 0.18, y: ly }
const right = { x: m.w * 0.18, y: ly }
pg.noStroke()
if (TRAITS.iris === "Null") {
pg.fill(0, 0, 100)
if (m.sight === "Mono") {
const center = { x: 0, y: ly }
drawEye(pg, center, rx, ry, m.sight, 0)
} else if (m.sight === "Verge") {
drawVerticalAlmondTotal(pg, rx, ry, ly, m.w, 0)
} else {
drawEye(pg, left, rx, ry, m.sight, 0)
drawEye(pg, right, rx, ry, m.sight, 0)
}
} else if (TRAITS.iris === "Fury") {
pg.fill(0, 100, 100)
if (m.sight === "Mono") {
const center = { x: 0, y: ly }
drawEye(pg, center, rx, ry, m.sight, 0)
} else if (m.sight === "Verge") {
drawVerticalAlmondTotal(pg, rx, ry, ly, m.w, 0)
} else {
drawEye(pg, left, rx, ry, m.sight, 0)
drawEye(pg, right, rx, ry, m.sight, 0)
}
} else if (TRAITS.iris === "Plasma") {
pg.fill(185, 100, 100)
if (m.sight === "Mono") {
const center = { x: 0, y: ly }
drawEye(pg, center, rx, ry, m.sight, 0)
} else if (m.sight === "Verge") {
drawVerticalAlmondTotal(pg, rx, ry, ly, m.w, 0)
} else {
drawEye(pg, left, rx, ry, m.sight, 0)
drawEye(pg, right, rx, ry, m.sight, 0)
}
} else if (TRAITS.iris === "Omnia") {
const cycleSpeed = 0.08
const palette = PARAMS.palette
const complementaryHues = palette.map(c => {
const col = color(c)
const h = hue(col)
return (h + 180) % 360
})
const cyclePosition = (millis() * cycleSpeed) % (complementaryHues.length * 100)
const colorIndex = floor(cyclePosition / 100) % complementaryHues.length
const nextIndex = (colorIndex + 1) % complementaryHues.length
const blend = (cyclePosition % 100) / 100
const currentHue = lerp(complementaryHues[colorIndex], complementaryHues[nextIndex], blend)
pg.fill(currentHue, 100, 100)
if (m.sight === "Mono") {
const center = { x: 0, y: ly }
drawEye(pg, center, rx, ry, m.sight, 0)
} else if (m.sight === "Verge") {
drawVerticalAlmondTotal(pg, rx, ry, ly, m.w, 0)
} else {
drawEye(pg, left, rx, ry, m.sight, 0)
drawEye(pg, right, rx, ry, m.sight, 0)
}
} else if (TRAITS.iris === "Abyss") {
const strokeW = m.w * 0.03
pg.fill(0, 0, 100)
if (m.sight === "Mono") {
const center = { x: 0, y: ly }
drawEye(pg, center, rx, ry, m.sight, strokeW)
} else if (m.sight === "Verge") {
drawVerticalAlmondTotal(pg, rx, ry, ly, m.w, strokeW)
} else {
drawEye(pg, left, rx, ry, m.sight, strokeW)
drawEye(pg, right, rx, ry, m.sight, strokeW)
}
pg.erase()
if (m.sight === "Mono") {
const center = { x: 0, y: ly }
drawEye(pg, center, rx, ry, m.sight, 0)
} else if (m.sight === "Verge") {
drawVerticalAlmondTotal(pg, rx, ry, ly, m.w, 0)
} else {
drawEye(pg, left, rx, ry, m.sight, 0)
drawEye(pg, right, rx, ry, m.sight, 0)
}
pg.noErase()
}
pg.pop()
}
function drawMaskEyesOmniaBase(pg, m) {
pg.push()
pg.translate(m.x, m.y)
pg.rotate(PARAMS.axisLock ? 0 : m.rot)
const rx = m.w * 0.22
const ry = m.h * 0.13
const ly = -m.h * 0.12
const left = { x: -m.w * 0.18, y: ly }
const right = { x: m.w * 0.18, y: ly }
pg.noStroke()
pg.fill(0, 0, 100) // White fill - will be tinted
if (m.sight === "Mono") {
const center = { x: 0, y: ly }
drawEye(pg, center, rx, ry, m.sight, 0)
} else if (m.sight === "Verge") {
drawVerticalAlmondTotal(pg, rx, ry, ly, m.w, 0)
} else {
drawEye(pg, left, rx, ry, m.sight, 0)
drawEye(pg, right, rx, ry, m.sight, 0)
}
pg.pop()
}
function getOmniaColor() {
const cycleSpeed = 0.08
const palette = PARAMS.palette
const complementaryHues = palette.map(c => {
const col = color(c)
const h = hue(col)
return (h + 180) % 360
})
const cyclePosition = (millis() * cycleSpeed) % (complementaryHues.length * 100)
const colorIndex = floor(cyclePosition / 100) % complementaryHues.length
const nextIndex = (colorIndex + 1) % complementaryHues.length
const blend = (cyclePosition % 100) / 100
const currentHue = lerp(complementaryHues[colorIndex], complementaryHues[nextIndex], blend)
return color(currentHue, 100, 100)
}
function drawMaskSilhouette(pg, m) {
pg.push()
pg.translate(m.x, m.y)
pg.rotate(PARAMS.axisLock ? 0 : m.rot)
pg.noStroke()
pg.fill(255)
drawMaskShape(pg, m)
drawOrnaments(pg, m)
drawTusks(pg, m)
drawEyes(pg, m)
pg.push()
pg.erase()
carveMouth(pg, m)
carveNose(pg, m)
carveCutouts(pg, m)
pg.noErase()
pg.pop()
pg.pop()
}
function drawMaskShape(pg, m) {
const pts = silhouettePoints(m.w, m.h, m.edgeStyle)
if (m.edgeStyle === "Curved") {
pg.beginShape()
const first = pts[0], last = pts[pts.length - 1]
pg.curveVertex(last.x, last.y)
for (const p of pts) pg.curveVertex(p.x, p.y)
pg.curveVertex(first.x, first.y)
pg.curveVertex(pts[1].x, pts[1].y)
pg.endShape(CLOSE)
} else {
pg.beginShape()
for (const p of pts) pg.vertex(p.x, p.y)
pg.endShape(CLOSE)
}
}
function stylizeEdge(p, style, snap) {
if (style === "Faceted") {
return { x: round(p.x / snap) * snap, y: round(p.y / snap) * snap }
}
if (style === "Straight") {
const ax = abs(p.x) > abs(p.y) ? { x: p.x, y: round(p.y / snap) * snap } : { x: round(p.x / snap) * snap, y: p.y }
return ax
}
return p
}
function silhouettePoints(w, h, edgeStyle) {
const bw = w * 0.5, bh = h * 0.5
let base = [
{ x: 0, y: -bh * 0.92 },
{ x: bw * 0.45, y: -bh * 0.78 },
{ x: bw * 0.68, y: -bh * 0.35 },
{ x: bw * 0.72, y: bh * 0.05 },
{ x: bw * 0.58, y: bh * 0.55 },
{ x: 0, y: bh * 0.72 },
{ x: -bw * 0.58, y: bh * 0.55 },
{ x: -bw * 0.72, y: bh * 0.05 },
{ x: -bw * 0.68, y: -bh * 0.35 },
{ x: -bw * 0.45, y: -bh * 0.78 },
]
const snap = min(w, h) * (edgeStyle === "Faceted" ? 0.05 : 0.035)
base = base.map((p) => stylizeEdge(p, edgeStyle, snap))
return base
}
function drawTusks(pg, m) {
if (m.voice !== "Downfall") return
const y = m.h * 0.27
const tuskTopWidth = m.w * 0.12
const tuskTipWidth = m.w * 0.03
const tuskHeight = m.h * 0.25
const tuskSpacing = m.w * 0.18
pg.push()
pg.fill(255)
pg.noStroke()
pg.push()
pg.translate(-tuskSpacing, y)
pg.beginShape()
pg.vertex(-tuskTopWidth * 0.5, 0)
pg.bezierVertex(
-tuskTopWidth * 0.5, tuskHeight * 0.3,
-tuskTipWidth * 0.8, tuskHeight * 0.7,
-tuskTipWidth * 0.3, tuskHeight
)
pg.vertex(0, tuskHeight * 0.95)
pg.bezierVertex(
tuskTipWidth * 0.3, tuskHeight * 0.7,
tuskTopWidth * 0.3, tuskHeight * 0.3,
tuskTopWidth * 0.5, 0
)
pg.endShape(CLOSE)
pg.pop()
pg.push()
pg.translate(tuskSpacing, y)
pg.beginShape()
pg.vertex(-tuskTopWidth * 0.5, 0)
pg.bezierVertex(
-tuskTopWidth * 0.3, tuskHeight * 0.3,
-tuskTipWidth * 0.3, tuskHeight * 0.7,
0, tuskHeight * 0.95
)
pg.vertex(tuskTipWidth * 0.3, tuskHeight)
pg.bezierVertex(
tuskTipWidth * 0.8, tuskHeight * 0.7,
tuskTopWidth * 0.5, tuskHeight * 0.3,
tuskTopWidth * 0.5, 0
)
pg.endShape(CLOSE)
pg.pop()
pg.pop()
}
function drawEyes(pg, m) {
let eyeColor, strokeColor, strokeW;
if (TRAITS.iris === "Null") {
eyeColor = 255;
strokeColor = 0;
strokeW = m.w * 0.015;
} else if (TRAITS.iris === "Abyss") {
eyeColor = 0;
strokeColor = 255;
strokeW = m.w * 0.012;
} else {
eyeColor = 255;
strokeColor = 0;
strokeW = m.w * 0.012;
}
const rx = m.w * 0.22
const ry = m.h * 0.13
const ly = -m.h * 0.12
const left = { x: -m.w * 0.18, y: ly }
const right = { x: m.w * 0.18, y: ly }
pg.push()
pg.noStroke()
pg.fill(strokeColor)
if (m.sight === "Mono") {
const center = { x: 0, y: ly }
drawEye(pg, center, rx, ry, m.sight, strokeW)
} else if (m.sight === "Verge") {
drawVerticalAlmondTotal(pg, rx, ry, ly, m.w, strokeW)
} else {
drawEye(pg, left, rx, ry, m.sight, strokeW)
drawEye(pg, right, rx, ry, m.sight, strokeW)
}
pg.fill(eyeColor)
if (m.sight === "Mono") {
const center = { x: 0, y: ly }
drawEye(pg, center, rx, ry, m.sight, 0)
} else if (m.sight === "Verge") {
drawVerticalAlmondTotal(pg, rx, ry, ly, m.w, 0)
} else {
drawEye(pg, left, rx, ry, m.sight, 0)
drawEye(pg, right, rx, ry, m.sight, 0)
}
pg.pop()
}
function drawVerticalAlmondTotal(pg, rx, ry, ly, maskWidth, strokeW = 0) {
const almondWidth = rx * 0.5
const almondHeight = ry * 1.8
const spacing = maskWidth * 0.15
const w = almondWidth + strokeW * 2
const h = almondHeight + strokeW * 2
for (let pos of [-spacing, 0, spacing]) {
pg.push()
pg.translate(pos, ly)
const width = pos === 0 ? w * 1.1 : w
const height = pos === 0 ? h : h
pg.beginShape()
pg.vertex(0, -height / 2)
pg.bezierVertex(
width * 0.5, -height * 0.3,
width * 0.5, height * 0.3,
0, height / 2
)
pg.bezierVertex(
-width * 0.5, height * 0.3,
-width * 0.5, -height * 0.3,
0, -height / 2
)
pg.endShape(CLOSE)
pg.pop()
}
}
function drawEye(pg, c, rx, ry, type, strokeW = 0) {
pg.push()
pg.translate(c.x, c.y)
pg.rectMode(CENTER)
const hasPupil = type.includes("with Pupil") && TRAITS.count !== "Conflux"
if (type === "Core") {
pg.ellipse(0, 0, rx * 1.0 + strokeW * 2, ry * 2 + strokeW * 2)
if (hasPupil && strokeW === 0) {
pg.push()
pg.fill(0, 0, 0)
const pupilWidth = min(rx, ry) * 0.1
const pupilHeight = ry * 1.6
pg.ellipse(0, -ry * 0.25, pupilWidth, pupilHeight)
pg.pop()
}
} else if (type === "Lune") {
pg.push()
const crescentRadius = ry * 0.7 + strokeW
const cutoutRadius = ry * 0.95
const cutoutOffset = ry * 0.4
pg.beginShape()
for (let a = 0; a <= PI; a += PI / 20) {
pg.vertex(cos(a) * crescentRadius, sin(a) * crescentRadius - cutoutOffset)
}
for (let a = PI; a >= 0; a -= PI / 20) {
pg.vertex(cos(a) * cutoutRadius, sin(a) * cutoutRadius - cutoutOffset)
}
pg.endShape(CLOSE)
pg.pop()
} else if (type === "Teardrop") {
pg.push()
const tearWidth = rx * 0.9 + strokeW
const tearHeight = ry * 1.4 + strokeW
const pointOffset = tearWidth * 0.7
const pointDir = c.x < 0 ? 1 : -1
pg.beginShape()
pg.vertex(pointDir * pointOffset, 0)
pg.bezierVertex(
pointDir * pointOffset * 0.3, -tearHeight * 0.5,
-pointDir * tearWidth * 0.3, -tearHeight * 0.6,
-pointDir * tearWidth * 0.5, 0
)
pg.bezierVertex(
-pointDir * tearWidth * 0.3, tearHeight * 0.6,
pointDir * pointOffset * 0.3, tearHeight * 0.5,
pointDir * pointOffset, 0
)
pg.endShape(CLOSE)
pg.pop()
} else if (type === "Mono") {
const visorWidth = rx * 2.0 + strokeW * 2
const visorHeight = ry * 0.8 + strokeW * 2
const visorRadius = visorHeight * 0.4
pg.rect(0, 0, visorWidth, visorHeight, visorRadius)
} else if (type === "Echo") {
const ovalWidth = rx * 1.2 + strokeW * 2
const ovalHeight = ry * 0.35 + strokeW * 2
const gap = ry * 0.5
pg.ellipse(0, -gap, ovalWidth, ovalHeight)
pg.ellipse(0, 0, ovalWidth * 1.1, ovalHeight)
pg.ellipse(0, gap, ovalWidth, ovalHeight)
} else if (type === "Slate") {
const rectWidth = rx * 1.0 + strokeW * 2
const rectHeight = ry * 0.4 + strokeW * 2
const gap = ry * 0.9
const cornerRadius = rectHeight
pg.rect(0, -gap, rectWidth, rectHeight, cornerRadius)
pg.rect(0, 0, rectWidth * 1.0, rectHeight, rectHeight * 1.0)
pg.rect(0, gap, rectWidth, rectHeight, rectHeight * 0.5)
} else if (type === "Vert") {
const segments = 5
const segWidth = rx * 0.33 + strokeW * 2
const totalHeight = ry * 1.6
const segHeight = totalHeight / segments + strokeW * 2
const gap = segHeight * 0.1
for (let i = 0; i < segments; i++) {
const y = (i - (segments - 1) / 2) * (totalHeight / segments)
pg.ellipse(0, y, segWidth, segHeight - gap)
}
} else if (type === "Signal") {
const dashes = 3
const dashWidth = rx * 1.2 / dashes + strokeW * 2
const dashHeight = ry * 0.6 + strokeW * 2
const gap = dashWidth * 0.25
for (let i = 0; i < dashes; i++) {
const x = (i - (dashes - 1) / 2) * (rx * 1.2 / dashes)
pg.rect(x, 0, dashWidth - gap, dashHeight, dashHeight * 0.2)
}
} else if (type === "Pierce") {
const dots = 1
const dotSize = min(rx, ry) * 0.75 + strokeW * 2
const spacing = rx * 0.5
for (let i = 0; i < dots; i++) {
const x = (i - (dots - 1) / 2) * spacing
pg.circle(x, 0, dotSize)
}
} else if (type === "Cross") {
const crossWidth = rx * 0.3 + strokeW * 2
const crossHeight = ry * 1.6 + strokeW * 2
pg.rect(0, 0, crossWidth, crossHeight)
pg.rect(0, 0, crossHeight * 0.6, crossWidth)
} else if (type === "Cut") {
const slitCount = 3
const slitWidth = rx * 0.7 + strokeW * 2
const slitHeight = ry * 0.2 + strokeW * 2
const gap = ry * 0.6
for (let i = 0; i < slitCount; i++) {
const y = (i - (slitCount - 1) / 2) * gap
pg.rect(0, y, slitWidth, slitHeight)
}
}
else {
pg.rect(0, 0, rx * 1.2 + strokeW * 2, ry * 0.4 + strokeW * 2, ry * 0.2)
}
pg.pop()
}
function carveMouth(pg, m) {
const y = m.h * 0.22
if (TRAITS.count === "Conflux") {
pg.push()
const translateX = m.maskIndex === 0 ? m.w * 0.18 : -m.w * 0.18
pg.translate(translateX, 0)
}
pg.rectMode(CENTER)
if (m.voice === "Still") {
pg.rect(0, y, m.w * 0.35, m.h * 0.03)
} else if (m.voice === "Prowl") {
pg.ellipse(0, y, m.w * 0.09, m.h * 0.4)
} else if (m.voice === "Forge") {
pg.rect(0, y, m.w * 0.28, m.h * 0.06, m.h * 0.01)
} else if (m.voice === "Sunder") {
const segmentCount = 4
const totalWidth = m.w * 0.25
const segmentWidth = totalWidth / segmentCount
const segmentHeight = m.h * 0.04
const gap = segmentWidth * 0.15
for (let i = 0; i < segmentCount; i++) {
const x = (i - (segmentCount - 1) / 2) * segmentWidth
pg.rect(x, y, segmentWidth - gap, segmentHeight, segmentHeight * 0.1)
}
} else if (m.voice === "Hollow") {
pg.rect(0, y, m.w * 0.35, m.h * 0.02)
} else if (m.voice === "Devour") {
pg.beginShape()
const points = 12
const width = m.w * 0.4
const height = m.h * 0.1
for (let i = 0; i <= points; i++) {
const x = map(i, 0, points, -width / 2, width / 2)
const yOffset = (i % 2 === 0) ? -height / 2 : height / 2
pg.vertex(x, y + yOffset)
}
pg.endShape()
pg.strokeWeight(m.h * 0.01)
pg.noFill()
pg.beginShape()
for (let i = 0; i <= points; i++) {
const x = map(i, 0, points, -width / 2, width / 2)
const yOffset = (i % 2 === 0) ? -height / 2 : height / 2
pg.vertex(x, y + yOffset)
}
pg.endShape()
pg.noStroke()
pg.fill(255)
} else if (m.voice === "Viper") {
const fangWidth = m.w * 0.06
const fangHeight = m.h * 0.08
const fangSpacing = m.w * 0.15
pg.push()
pg.translate(-fangSpacing, y)
pg.triangle(0, fangHeight, -fangWidth / 2, 0, fangWidth / 2, 0)
pg.pop()
pg.push()
pg.translate(fangSpacing, y)
pg.triangle(0, fangHeight, -fangWidth / 2, 0, fangWidth / 2, 0)
pg.pop()
} else if (m.voice === "Bind") {
const mouthWidth = m.w * 0.35
const mouthHeight = m.h * 0.015
pg.rect(0, y, mouthWidth, mouthHeight)
const stitchCount = 6
const stitchHeight = m.h * 0.03
const stitchWidth = m.w * 0.01
for (let i = 0; i < stitchCount; i++) {
const x = (i - (stitchCount - 1) / 2) * (mouthWidth / (stitchCount - 1))
pg.rect(x, y, stitchWidth, stitchHeight)
}
} else if (m.voice === "Downfall") {
pg.rect(0, y, m.w * 0.25, m.h * 0.015)
} else if (m.voice === "Stun") {
const mouthWidth = m.h * 0.12
const mouthHeight = m.h * 0.06
pg.push()
pg.translate(0, y + mouthHeight)
pg.beginShape()
for (let a = PI; a <= TWO_PI; a += PI / 20) {
const x = cos(a) * mouthWidth / 2
const yOffset = sin(a) * mouthHeight
pg.vertex(x, yOffset)
}
pg.vertex(mouthWidth / 2, 0)
pg.vertex(-mouthWidth / 2, 0)
pg.endShape(CLOSE)
pg.pop()
} else if (m.voice === "Grate") {
const barCount = 4
const barWidth = m.w * 0.3
const barHeight = m.h * 0.03
const spacing = m.h * 0.04
for (let i = 0; i < barCount; i++) {
const barY = y + (i - (barCount - 1) / 2) * spacing
pg.rect(0, barY, barWidth, barHeight)
}
} else if (m.voice === "Ease") {
pg.push()
pg.translate(0, y)
const waveWidth = m.w * 0.4
const waveHeight = m.h * 0.025
pg.beginShape()
const steps = 30
for (let i = 0; i <= steps; i++) {
const t = i / steps
const x = map(t, 0, 1, -waveWidth / 2, waveWidth / 2)
const waveY = sin(t * PI * 3) * waveHeight
pg.vertex(x, waveY)
}
for (let i = steps; i >= 0; i--) {
const t = i / steps
const x = map(t, 0, 1, -waveWidth / 2, waveWidth / 2)
const waveY = sin(t * PI * 3) * waveHeight + m.h * 0.015
pg.vertex(x, waveY)
}
pg.endShape(CLOSE)
pg.pop()
} else {
pg.rect(0, y, m.w * 0.45, m.h * 0.018)
}
if (TRAITS.count === "Conflux") {
pg.pop()
}
}
function carveNose(pg, m) {
if (m.scent === "Sealed") return
const y = m.h * 0.05 + 20
if (TRAITS.count === "Conflux") {
pg.push()
const translateX = m.maskIndex === 0 ? m.w * 0.18 : -m.w * 0.18
pg.translate(translateX, 0)
}
pg.rectMode(CENTER)
if (m.scent === "Aero") {
pg.rect(0, y, m.w * 0.05, m.h * 0.07)
} else if (m.scent === "Sego") {
const segments = 3
const totalHeight = m.h * 0.12
const segHeight = totalHeight / segments
const gap = segHeight * 0.25
for (let i = 0; i < segments; i++) {
const segY = y + (i - (segments - 1) / 2) * segHeight
pg.rect(0, segY, m.w * 0.05, segHeight - gap)
}
} else if (m.scent === "Duos") {
const dotSize = m.w * 0.025
const spacing = m.w * 0.04
pg.circle(-spacing / 2, y, dotSize)
pg.circle(spacing / 2, y, dotSize)
} else if (m.scent === "Jewel") {
pg.push()
pg.translate(0, y)
const size = m.w * 0.04
pg.quad(0, -size, size, 0, 0, size, -size, 0)
pg.pop()
} else if (m.scent === "Dot") {
const dotSize = m.w * 0.03
pg.circle(0, y, dotSize)
} else if (m.scent === "Aexo") {
pg.push()
pg.translate(0, y)
pg.triangle(0, m.h * 0.04, -m.w * 0.03, -m.h * 0.04, m.w * 0.03, -m.h * 0.04)
pg.pop()
} else if (m.scent === "Tri") {
const dotSize = m.w * 0.02
const spacing = m.h * 0.04
pg.circle(0, y - spacing, dotSize)
pg.circle(0, y, dotSize)
pg.circle(0, y + spacing, dotSize)
}
if (TRAITS.count === "Conflux") {
pg.pop()
}
}
function carveCutouts(pg, m) {
if (m.hollows === "Whole") return
if (m.hollows === "Cleave") {
if (TRAITS.count === "Conflux") {
const isLeftMask = m.x < width / 2
if (isLeftMask) {
pg.ellipse(-m.w * 0.28, m.h * 0.08, m.w * 0.08, m.h * 0.08)
} else {
pg.ellipse(m.w * 0.28, m.h * 0.08, m.w * 0.08, m.h * 0.08)
}
} else {
pg.ellipse(-m.w * 0.28, m.h * 0.08, m.w * 0.08, m.h * 0.08)
pg.ellipse(m.w * 0.28, m.h * 0.08, m.w * 0.08, m.h * 0.08)
}
} else if (m.hollows === "Mark") {
pg.ellipse(0, -m.h * 0.32, m.w * 0.08, m.h * 0.08)
} else if (m.hollows === "Maw") {
pg.rectMode(CENTER)
const hollowX = m.w * 0.30
const hollowY = m.h * 0.18
const hollowWidth = m.w * 0.18
const hollowHeight = m.h * 0.28
if (TRAITS.count === "Conflux") {
const isLeftMask = m.maskIndex === 0
if (isLeftMask) {
pg.push