function rand(array){ var rand = array[Math.floor(Math.random()*array.length)]; return rand; } var linecap = rand(['round']); function bottomCall(){ context.save(); context.translate(0,height/17); for( var i = 0; i < 200; i++ ) { bottomwing(); } context.restore(); } function topCall(){ screenarray = ["darken", "overlay", "lighten", "darken", "overlay"]; context.save(); context.translate(0,height/17); for( var i = 0; i < 700; i++ ) { topwing(); } context.restore(); } function bottomwing(){ screenarray = ["darken", "overlay", "lighten", "darken", "overlay"]; context.lineCap = linecap; context.strokeStyle = rand(colorarray2); context.globalCompositeOperation = rand(screenarray); var wiggle = (Math.floor(Math.random()*200)*0.5); context.lineWidth = Math.floor(Math.random()*100); context.globalAlpha = Math.floor(Math.random()*80)*0.0005; var randwidth= (Math.floor(Math.random()*width*3)+width/3); var randheight= (Math.floor(Math.random()*height)+height/3); context.save(); context.translate(width/1.9,height/1.92); context.scale(-1, 1); context.beginPath(); context.moveTo(0+wiggle,0); context.rotate(-rearWingAngle); context.lineTo(randwidth, randheight); context.stroke(); context.restore(); context.save(); context.translate(width/2.1,height/1.92); context.scale(1, 1); context.beginPath(); context.moveTo(0+wiggle,0); context.rotate(-rearWingAngle); context.lineTo(randwidth, randheight); context.stroke(); context.restore(); /* context.beginPath(); context.moveTo(width/1.9,height/1.7); context.lineTo(width/1.9+randwidth, height/1.7 + randheight); context.globalAlpha = context.globalAlpha/2; context.lineTo(width/1.9+randwidth, height/1.7 + randheight); context.globalAlpha = context.globalAlpha*2; context.moveTo(width/2.1,height/1.7); context.lineTo(width/2.1-randwidth, height/1.7 + randheight); context.stroke(); context.globalAlpha = context.globalAlpha/2; context.lineTo(width/2.1-randwidth, height/1.7 + randheight); context.stroke(); */ } function topwing() { var wiggle = (Math.floor(Math.random()*200)*0.5); context.lineCap = linecap; context.strokeStyle = rand(colorarray); context.globalCompositeOperation = rand(screenarray); context.lineWidth = Math.floor(Math.random()*100); context.globalAlpha = Math.floor(Math.random()*80)*0.0005; var randwidth= (Math.floor(Math.random()*width*2)+width)/4; var randheight= (Math.floor(Math.random()*height*3))/2; context.save(); context.translate(width/2,height/2.12); context.scale(-1, 1); context.beginPath(); context.moveTo(0+wiggle,0); context.rotate(-wingAngle); context.lineTo(randwidth, randheight); context.stroke(); context.restore(); context.save(); context.translate(width/2,height/2.12); context.scale(1, 1); context.beginPath(); context.moveTo(0+wiggle,0); context.rotate(-wingAngle); context.lineTo(randwidth, randheight); context.stroke(); context.restore(); // } function body(){ context.save(); context.translate(0,0); context.translate(width/2, height/2.12); //fill abdomen context.save(); context.globalCompositeOperation = "source-over"; context.globalAlpha = 0.9; context.beginPath(); context.moveTo(0,abdomenTop); context.bezierCurveTo(0,abdomenFirstY-5,abdomenWidth,abdomenSecondY-5,0,abdomenBottom-5); context.scale(-1, 1); context.moveTo(0,abdomenTop); context.bezierCurveTo(0,abdomenFirstY-5,abdomenWidth,abdomenSecondY-5,0,abdomenBottom-5); context.fillStyle= "#999"; context.fill(); context.closePath(); context.restore(); //fuzz context.globalAlpha = 1; context.globalCompositeOperation = "difference"; context.lineWidth = 0.4; var fuzziness = 20; //Math.floor(Math.random()*200); // 0 - 50 scale of fuzzy //abdomen for( var i = 0; i < abdomenWidth; i++ ) { context.save(); //context.globalCompositeOperation = "difference"; context.lineWidth = (Math.floor(Math.random()*30)*0.1)+0.1; context.strokeStyle = rand(bodycolorarray); context.globalAlpha = Math.floor(Math.random()*20)*0.1; context.lineCap = "round"; context.beginPath(); context.moveTo(0,abdomenTop); context.bezierCurveTo(0,abdomenFirstY,abdomenWidth-i,abdomenSecondY,0,abdomenBottom); context.stroke(); context.closePath(); context.scale(-1, 1); context.beginPath(); context.moveTo(0,abdomenTop); context.bezierCurveTo(0,abdomenFirstY,abdomenWidth-i,abdomenSecondY,0,abdomenBottom); context.stroke(); context.closePath(); context.restore(); } //clip path for pattern zone context.save(); context.globalCompositeOperation = "source-over"; context.globalAlpha = 1; context.lineWidth = 13; context.beginPath(); context.moveTo(0,headBottom); context.bezierCurveTo(0,headFirstY,headWidth,headSecondY,0,headTop); context.moveTo(0,thoraxTop); context.bezierCurveTo(0,thoraxFirstY,thoraxWidth,thoraxSecondY,0,thoraxBottom); context.moveTo(0,abdomenTop); context.bezierCurveTo(0,abdomenFirstY,abdomenWidth,abdomenSecondY,0,abdomenBottom); context.scale(-1, 1); context.moveTo(0,headBottom); context.bezierCurveTo(0,headFirstY,headWidth,headSecondY,0,headTop); context.moveTo(0,thoraxTop); context.bezierCurveTo(0,thoraxFirstY,thoraxWidth,thoraxSecondY,0,thoraxBottom); context.moveTo(0,abdomenTop); context.bezierCurveTo(0,abdomenFirstY,abdomenWidth,abdomenSecondY,0,abdomenBottom); context.closePath(); context.clip(); context.beginPath(); //pattern zone!!! context.save(); context.lineCap = "round"; context.translate(0, abdomenTop); var patternMarkHeight = 2; var marksAcross = 48; var marksTall = (abdomenBottom - abdomenTop) / patternMarkHeight + 1; var xOffset; var yOffset; var patternWidth = abdomenWidth; var functionValue; var xPatternOffset = 1.0 * Math.random(); var xMultiplier = Math.random() * 2.0; var yMultiplier = 1.0 * (Math.random() * 2.0 - 1.0); var slowYPatternOffset = 2 * Math.PI * Math.random(); var slowYMultiplier = Math.random(); var colorPeak = rand(bodycolorarray); var compositeModePeak = rand(screenarray); var opacityPeak = Math.random() * 0.25 + 0.1; var colorMid = rand(hairColor); var compositeModeMid = rand(screenarray); var opacityMid = Math.random() * 0.25 + 0.1; var peakThreshold = 0.9; var midThreshold = 0.1; for (var iY = 0; iY < marksTall; iY ++) { yOffset = iY * (abdomenBottom - abdomenTop) / marksTall; for (var iX = 0; iX < marksAcross; iX ++) { context.save(); //in the pattern zone!!! /* x x x x x x x x x x x x x x x x x */ context.beginPath(); context.lineWidth = Math.random() * 3.0 + 2.0; functionValue = getAbdomenFunctionValue(iX / marksAcross, iY / marksTall, xPatternOffset, xMultiplier, yMultiplier, slowYMultiplier, slowYPatternOffset); if (functionValue > peakThreshold) { context.strokeStyle = colorPeak; context.globalCompositeMode = compositeModePeak; context.globalAlpha = opacityPeak; } else if (functionValue > midThreshold) { context.strokeStyle = colorMid; context.globalCompositeMode = compositeModeMid; context.globalAlpha = opacityMid; } //context.globalAlpha = 0.25 * (0.75 + Math.random() * 0.5) * functionValue; xOffset = 0.5 * patternWidth * Math.cos(Math.PI * iX / marksAcross); context.moveTo(xOffset, yOffset); context.lineTo(xOffset, yOffset + patternMarkHeight); context.stroke(); context.restore(); } } context.restore(); //end of pattern zone!!! context.closePath(); context.restore(); //abdomen fuzz context.save(); context.beginPath(); context.bezierCurveTo(0,abdomenFirstY+3,abdomenWidth+3,abdomenSecondY+4,0,abdomenBottom+5); context.closePath(); context.clip(); for (var n = 0; n < fuzziness; n++){ for (var i = 0; i < abdomenBottom; i++){ context.strokeStyle = rand(bodycoloroptions); context.beginPath(); var littleX = Math.floor(Math.random()*abdomenWidth); context.moveTo(littleX,abdomenTop + i); context.lineTo(littleX+ Math.floor(Math.random()*10)*0.1, abdomenTop + i + Math.floor(Math.random()*10)); context.stroke(); context.closePath(); } } context.restore(); //abdomen fuzz reverse context.save(); context.scale(-1, 1); context.beginPath(); context.bezierCurveTo(0,abdomenFirstY+3,abdomenWidth+3,abdomenSecondY+4,0,abdomenBottom+5); context.closePath(); context.clip(); for (var n = 0; n < fuzziness; n++){ for (var i = 0; i < abdomenBottom; i++){ context.strokeStyle = rand(bodycoloroptions); context.beginPath(); var littleX = Math.floor(Math.random()*abdomenWidth); context.moveTo(littleX,abdomenTop + i); context.lineTo(littleX+ Math.floor(Math.random()*10)*0.1, abdomenTop + i + Math.floor(Math.random()*10)); context.stroke(); context.closePath(); } } context.restore(); for (i = 0; i < thoraxWidth*4; i++) { context.scale(-1, 1); context.strokeStyle = rand(bodycolorarray); context.globalCompositeOperation = "multiply"; context.save(); context.lineWidth = 0.7; context.globalAlpha = 0.2; context.beginPath(); context.moveTo(-3+i/14, abdomenTop); context.lineTo(Math.random()*5 + i/12, abdomenTop + Math.random()*abdomenBottom/7); context.stroke(); context.stroke(); context.closePath(); context.restore(); } //fill thorax and head context.save(); context.globalCompositeOperation = "source-over"; context.globalAlpha = 0.9; context.beginPath(); context.moveTo(0,headBottom); context.bezierCurveTo(0,headFirstY,headWidth,headSecondY,0,headTop); context.moveTo(0,thoraxTop); context.bezierCurveTo(0,thoraxFirstY,thoraxWidth,thoraxSecondY,0,thoraxBottom); context.scale(-1, 1); context.moveTo(0,headBottom); context.bezierCurveTo(0,headFirstY,headWidth,headSecondY,0,headTop); context.moveTo(0,thoraxTop); context.bezierCurveTo(0,thoraxFirstY,thoraxWidth,thoraxSecondY,0,thoraxBottom); context.fillStyle= "#999"; context.fill(); context.closePath(); context.restore(); //head for( var i = 0; i < headWidth; i++ ) { context.save(); context.globalCompositeOperation = "difference"; context.lineWidth = (Math.floor(Math.random()*30)*0.1)+0.1; context.strokeStyle = rand(bodycolorarray); context.globalAlpha = Math.floor(Math.random()*20)*0.1; context.lineCap = "round"; context.beginPath(); context.moveTo(0,headBottom); context.bezierCurveTo(0,headFirstY,headWidth-i,headSecondY,0,headTop); context.stroke(); context.closePath(); context.scale(-1, 1); context.beginPath(); context.moveTo(0,headBottom); context.bezierCurveTo(0,headFirstY,headWidth-i,headSecondY,0,headTop); context.stroke(); context.closePath(); context.restore(); } //thorax for( var i = 0; i < thoraxWidth; i++ ) { context.save(); context.globalCompositeOperation = "difference"; context.lineWidth = (Math.floor(Math.random()*30)*0.1)+0.1; context.strokeStyle = rand(bodycolorarray); context.globalAlpha = Math.floor(Math.random()*20)*0.1; context.lineCap = "round"; context.beginPath(); context.moveTo(0,thoraxTop); context.bezierCurveTo(0,thoraxFirstY,thoraxWidth-i,thoraxSecondY,0,thoraxBottom); context.stroke(); context.closePath(); context.scale(-1, 1); context.beginPath(); context.moveTo(0,thoraxTop); context.bezierCurveTo(0,thoraxFirstY,thoraxWidth-i,thoraxSecondY,0,thoraxBottom); context.stroke(); context.closePath(); context.restore(); } //headfuzz context.save(); context.scale(-1, 1); context.beginPath(); context.bezierCurveTo(0,headFirstY,headWidth,headSecondY,0,headTop); context.closePath(); context.clip(); for (var n = 0; n < fuzziness; n++){ for (var i = 0; i < headBottom + height/28; i++){ context.strokeStyle = rand(bodycoloroptions); context.beginPath(); var littleX = Math.floor(Math.random()*headWidth); context.moveTo(littleX,headTop + i); context.lineTo(littleX+ Math.floor(Math.random()*10)*0.1, headTop + i + Math.floor(Math.random()*10)); context.stroke(); context.closePath(); } } context.restore(); //headfuzz reverse context.save(); context.beginPath(); context.bezierCurveTo(0,headFirstY,headWidth,headSecondY,0,headTop); context.closePath(); context.clip(); for (var n = 0; n < fuzziness; n++){ for (var i = 0; i < headBottom + height/28; i++){ context.strokeStyle = rand(bodycoloroptions); context.beginPath(); var littleX = Math.floor(Math.random()*headWidth); context.moveTo(littleX,headTop + i); context.lineTo(littleX+ Math.floor(Math.random()*10)*0.1, headTop + i + Math.floor(Math.random()*10)); context.stroke(); context.closePath(); } } context.restore(); //thoraxfuzz context.save(); context.scale(-1, 1); context.beginPath(); context.bezierCurveTo(0,thoraxFirstY,thoraxWidth,thoraxSecondY,0,thoraxBottom); context.closePath(); context.clip(); for (var n = 0; n < fuzziness; n++){ for (var i = 0; i < thoraxBottom + height/28; i++){ context.strokeStyle = rand(bodycoloroptions); context.beginPath(); var littleX = Math.floor(Math.random()*thoraxWidth); context.moveTo(littleX,thoraxTop + i); context.lineTo(littleX+ Math.floor(Math.random()*10)*0.1, thoraxTop + i + Math.floor(Math.random()*10)); context.stroke(); context.closePath(); } } context.restore(); //thoraxfuzz reverse context.save(); context.beginPath(); context.bezierCurveTo(0,thoraxFirstY,thoraxWidth,thoraxSecondY,0,thoraxBottom); context.closePath(); context.clip(); for (var n = 0; n < fuzziness; n++){ for (var i = 0; i < thoraxBottom + height/28; i++){ context.strokeStyle = rand(bodycoloroptions); context.beginPath(); var littleX = Math.floor(Math.random()*thoraxWidth); context.moveTo(littleX,thoraxTop + i); context.lineTo(littleX+ Math.floor(Math.random()*10)*0.1, thoraxTop + i + Math.floor(Math.random()*10)); context.stroke(); context.closePath(); } } context.restore(); /* //clip path for pattern zone context.save(); context.globalCompositeOperation = "source-over"; context.globalAlpha = 1; context.lineWidth = 13; context.beginPath(); context.moveTo(0,headBottom); context.bezierCurveTo(0,headFirstY,headWidth,headSecondY,0,headTop); context.moveTo(0,thoraxTop); context.bezierCurveTo(0,thoraxFirstY,thoraxWidth,thoraxSecondY,0,thoraxBottom); context.moveTo(0,abdomenTop); context.bezierCurveTo(0,abdomenFirstY,abdomenWidth,abdomenSecondY,0,abdomenBottom); context.scale(-1, 1); context.moveTo(0,headBottom); context.bezierCurveTo(0,headFirstY,headWidth,headSecondY,0,headTop); context.moveTo(0,thoraxTop); context.bezierCurveTo(0,thoraxFirstY,thoraxWidth,thoraxSecondY,0,thoraxBottom); context.moveTo(0,abdomenTop); context.bezierCurveTo(0,abdomenFirstY,abdomenWidth,abdomenSecondY,0,abdomenBottom); context.closePath(); context.clip(); context.beginPath(); //pattern zone!!! context.closePath(); context.restore(); */ context.restore(); } function getAbdomenFunctionValue(lookupX, lookupY, xPatternOffset, xMultiplier, yMultiplier, slowYMultiplier, slowYPatternOffset) { lookupX = Math.abs(2 * lookupX - 1); var yFrequency = 10; var slowWave = Math.sin(2.0 * Math.PI * (slowYMultiplier * lookupY + slowYPatternOffset)); return Math.max(0, Math.min(1, ( Math.sin(yFrequency * 2 * Math.PI * lookupY) + Math.sin(xMultiplier * 2 * Math.PI * ((lookupX + xPatternOffset) + yMultiplier * lookupY)) + slowWave))); } function antennae(context, x, y, xOffset, scale) { // 📡 📡 📡 function getAntennaWaveValue(x, seed) { // 🐜 🐜 🐜 seedDRand(seed); var frequency0 = dRandomFloatIn(0.75, 1.5); var input = 2 * Math.PI * x; var masterAmplitude = 1.0; var amplitude0 = dRandomFloatIn(0.1, 0.25); var result = masterAmplitude * (amplitude0 * Math.sin(frequency0 * input)); return result; } function getAttenuationValue(x, seed) { // 🐝 🐝 🐝 seedDRand(seed); var input = 2 * Math.PI * x - Math.PI / 2; var result = 0.5 * (1.0 + Math.sin(input)); return result; } // fork between club and feathered variants var club = dRandomInt(5) == 0 ? true : false; var currentSeed = Math.floor(Math.random() * 982451497); seedDRand(currentSeed); var scaleAdjust = scale / -width; // remap to 0-1 range so it's a nice multiplier var radius = 0.1 * scale; context.globalAlpha = 1; context.globalCompositeOperation = "source-over"; var length = dRandomFloatIn(0.5 * scale, 0.8 * scale); var segmentCount = dRandomIn(24, 48); var segmentLength = length / segmentCount; var initialAngle = -Math.PI / 8 + dRandomFloatIn(-1 * Math.PI, -0.6 * Math.PI); // nudge the antenna start angle based on the wing angle var angleNudge = -(wingAngle - Math.PI / 12); initialAngle += angleNudge; if (dRandomInt(2) == 0) initialAngle = -Math.PI / 8 + dRandomFloatIn(-1 * Math.PI, -0.75 * Math.PI); var bendAdjust = 24 / segmentCount; // to compensate for more highly segmented antennae curling more var currentAngle; // feathering var featherLength = dRandomFloatIn(length * .005, length * .15); var featherAttenuation; var currentR; var currentG; var currentB; // pull a color from moth wing color array var sourceColor = colorarray2[dRandomInt(colorarray2.length)]; sourceColor = sourceColor.substring(1); sourceColor = parseInt(sourceColor, 16); var baseR = (sourceColor >> 16) & 0xFF; var baseG = (sourceColor >> 8) & 0xFF; var baseB = sourceColor & 0xFF; var tipR = 0; var tipG = 0; var tipB = 0; var blend; var clubLength = 0.25; var antennaBendStrength = [1 + jitter(0.25), 1 + jitter(0.25)]; for (sign = -1; sign <= 1; sign += 2) { seedDRand(currentSeed); context.save(); context.lineCap = "round"; context.translate(x + sign * xOffset, y); context.rotate(sign * initialAngle); // this draws the spine of the antenna for (i = 0; i < 2 * segmentCount; i ++) { blend = i / (2 * segmentCount); featherAttenuation = getAttenuationValue(blend, currentSeed); context.lineWidth = 6 * scaleAdjust; if (club) { if (blend > 1 - clubLength) { context.lineWidth *= lerp(1, 3, (0.5 + 0.5 * Math.sin(2 * Math.PI * (blend - (1 - clubLength)) / clubLength - Math.PI / 2))); } } //if (blend > 0.75) // context.lineWidth *= (1 - (blend - 0.75) / 0.25); currentAngle = sign * 0.5 * getAntennaWaveValue(i / (2 * segmentCount), currentSeed); // vary bend strength if (sign == -1) currentAngle *= antennaBendStrength[0]; context.beginPath(); context.translate(0, 0.5 * segmentLength); context.moveTo(0, 0); context.rotate(currentAngle * bendAdjust); //context.globalAlpha = featherAttenuation; // here is the horrible string concatenation part currentR = (Math.floor((1 - featherAttenuation) * tipR + featherAttenuation * baseR)).toString(16); currentG = (Math.floor((1 - featherAttenuation) * tipG + featherAttenuation * baseG)).toString(16); currentB = (Math.floor((1 - featherAttenuation) * tipB + featherAttenuation * baseB)).toString(16); if (currentR.length < 2) currentR = "0" + currentR; if (currentG.length < 2) currentG = "0" + currentG; if (currentB.length < 2) currentB = "0" + currentB; context.strokeStyle = "#" + currentR + currentG + currentB; context.lineTo(0, segmentLength); context.stroke(); } context.restore(); context.save(); if (!club) { // this part draws the feathering along the sides context.save(); context.translate(x + sign * xOffset, y); context.rotate(sign * initialAngle); for (i = 0; i < 2 * segmentCount; i ++) { // here is the horrible string concatenation part currentR = (Math.floor((1 - featherAttenuation) * tipR + featherAttenuation * baseR)).toString(16); currentG = (Math.floor((1 - featherAttenuation) * tipG + featherAttenuation * baseG)).toString(16); currentB = (Math.floor((1 - featherAttenuation) * tipB + featherAttenuation * baseB)).toString(16); if (currentR.length < 2) currentR = "0" + currentR; if (currentG.length < 2) currentG = "0" + currentG; if (currentB.length < 2) currentB = "0" + currentB; featherAttenuation = getAttenuationValue(i / (2 * segmentCount), currentSeed); context.lineWidth = 12 * scaleAdjust; currentAngle = 0.5 * sign * getAntennaWaveValue(i / (2 * segmentCount), currentSeed); // vary bend strength if (sign == -1) currentAngle *= antennaBendStrength[0]; context.beginPath(); context.translate(0, 0.5 * segmentLength); context.moveTo(0, 0); context.rotate(currentAngle * bendAdjust); currentValue = (Math.floor(255 - featherAttenuation * 255)).toString(16); if (currentValue.length < 2) currentValue = "0" + currentValue; // feathering // tailward and headward extensions if (i % 2 == 0) { for (i2 = -1; i2 <= 1; i2 += 2) { context.save(); context.rotate(sign * i2 * Math.PI / 2); // draw the side-facing feather components; context.beginPath(); context.moveTo(0, 0); var featherGradient = context.createLinearGradient(0, 0, 0, featherAttenuation * featherLength); featherGradient.addColorStop("0", "#" + currentValue + currentValue + currentValue); featherGradient.addColorStop("1", "transparent"); context.strokeStyle = featherGradient; context.lineTo(0, featherAttenuation * featherLength); //context.stroke(); // hairs aligned with the perpendicular var lengthJitter = featherAttenuation * 8; var angleJitter = 0.1; var antennaHairLength = featherAttenuation * featherLength; //if (antennaHairLength > 3) { var baseNudge; if (true) { for (var i3 = 0; i3 < legHairiness * 4; i3 ++) { context.save(); context.strokeStyle = "#000000"; context.lineWidth = 2; context.globalAlpha = 0.1; context.beginPath(); //context.translate(); baseNudge = 0.25 * jitter(1) * 0.5 * segmentLength; context.moveTo(baseNudge, 8 * scaleAdjust); //context.rotate(jitter(angleJitter)); context.rotate(i3 * 0.01); var featherGradient2 = context.createLinearGradient(0, 0, 0, antennaHairLength); featherGradient2.addColorStop("0", "#000000"); featherGradient2.addColorStop("1", hairColor[dRandomInt(hairColor.length)]); context.strokeStyle = featherGradient2; context.lineTo(baseNudge, 0.75 * antennaHairLength + jitter(lengthJitter)); context.stroke(); context.restore(); } for (var i3 = 0; i3 < legHairiness * 16; i3 ++) { context.save(); context.strokeStyle = hairColor[dRandomInt(hairColor.length)]; context.lineWidth = 1; context.globalAlpha = 0.2; context.beginPath(); //context.translate(); baseNudge = 0.5 * jitter(1 - featherAttenuation) * 0.5 * segmentLength; context.moveTo(baseNudge, featherAttenuation * (4 * scaleAdjust) + jitter(2 * scaleAdjust)); //context.rotate(jitter(angleJitter)); context.rotate(i3 * 0.01); var featherGradient2 = context.createLinearGradient(0, 0, 0, antennaHairLength); featherGradient2.addColorStop("0", "#" + currentR + currentG + currentB); featherGradient2.addColorStop("1", hairColor[dRandomInt(hairColor.length)]); context.strokeStyle = featherGradient2; context.lineTo(baseNudge, antennaHairLength + jitter(lengthJitter)); context.stroke(); context.restore(); } } context.restore(); } } } } context.restore(); context.save(); context.lineCap = "round"; context.translate(x + sign * xOffset, y); context.rotate(Math.PI / 2 + sign * initialAngle); hairTuft(32, 8, 2, 0.7); context.restore(); } } function spots(spotx, spoty, spotsize, intensity){ for (i = 0; i < intensity; i ++) { var spotwiggle = (Math.floor(Math.random()*200)*0.05); var spotcolor = rand(colorarray); var spotlines = Math.floor(Math.random()*spotsize); var spotalpha = Math.floor(Math.random()*80)*0.001; var spotrotate = Math.floor(Math.random()*30)*0.0005; context.save(); context.globalCompositeOperation = "overlay"; context.lineCap = "round"; context.strokeStyle = spotcolor; context.lineWidth = spotlines; context.globalAlpha = spotalpha; //context.scale(1, 1); context.rotate(spotrotate); context.beginPath(); context.moveTo(spotx - spotwiggle, spoty + spotwiggle); context.lineTo(spotx, spoty); context.stroke(); context.restore(); /* context.save(); context.globalCompositeOperation = "overlay"; context.lineCap = "round"; context.strokeStyle = spotcolor; context.lineWidth = spotlines; context.globalAlpha = spotalpha; context.scale(-1, 1); context.rotate(spotrotate); context.beginPath(); context.moveTo(spotx/2 - spotwiggle, 0 + spotwiggle); context.lineTo(spotx/2, 0); context.stroke(); context.restore(); */ } } ////// noise gate function perlin_noise (noise_canvas) { var offscreen = document.getElementById("noise_canvas"), offscreen_context = offscreen.getContext ("2d"); offscreen.width = noise_canvas.width offscreen.height = noise_canvas.height var offscreen_id = offscreen_context.getImageData (0, 0, offscreen.width, offscreen.height), offscreen_pixels = offscreen_id.data for (var i = 0; i < offscreen_pixels.length; i += 4) { offscreen_pixels[i ] = offscreen_pixels[i + 1] = offscreen_pixels[i + 2] = Math.floor (Math.random () * 256) offscreen_pixels[i + 3] = 255 } offscreen_context.putImageData (offscreen_id, 0, 0) /* Scale random iterations onto the canvas to generate Perlin noise. */ for (var size = 4; size <= offscreen.width; size *= 2) { var x = Math.floor (Math.random () * (offscreen.width - size)), y = Math.floor (Math.random () * (offscreen.height - size)) offscreen_context.globalAlpha = 0.5 offscreen_context.drawImage (offscreen, x, y, size, size, 0, 0, noise_canvas.width, noise_canvas.height) } } function veins (wingXOffset, wingY, wingAngle, foreWingArc, currentSeed, scale, which, veinseed){ // console.log (wingXOffset + " , " + wingY + " , " + wingAngle + " , " + foreWingArc + " , " + currentSeed + " , " + scale); //yuck ///quadratic length function Point(x, y) { this.x = x; this.y = y; } function quadraticBezierLength(p0, p1, p2) { var a = new Point( p0.x - 2 * p1.x + p2.x, p0.y - 2 * p1.y + p2.y ); var b = new Point( 2 * p1.x - 2 * p0.x, 2 * p1.y - 2 * p0.y ); var A = 4 * (a.x * a.x + a.y * a.y); var B = 4 * (a.x * b.x + a.y * b.y); var C = b.x * b.x + b.y * b.y; var Sabc = 2 * Math.sqrt(A+B+C); var A_2 = Math.sqrt(A); var A_32 = 2 * A * A_2; var C_2 = 2 * Math.sqrt(C); var BA = B / A_2; return (A_32 * Sabc + A_2 * B * (Sabc - C_2) + (4 * C * A - B * B) * Math.log((2 * A_2 + BA + Sabc) / (BA + C_2))) / (4 * A_32); } ////// context.save(); context.translate(0,0); context.translate(width/2,height/2.12); context.rotate (-wingAngle * which); context.scale(which,1); var cellOneStartX = -11; var cellOneStartY = -10; var cellOneEndX = foreWingArc*wingY + cellOneStartX; var cellOneEndY = wingY/3 + cellOneStartY; var cellOneControlX = veinseed*cellOneEndX - cellOneStartX; var cellOneControlY = veinseed*cellOneEndY - cellOneStartY; var wingSegmentsOffMain = veinseed*1; var segmentNumber = veinseed*70 + 70; // higher = less var mothCells = quadraticBezierLength({x:cellOneStartX, y:cellOneStartY}, {x:cellOneControlX, y:cellOneControlY}, {x:cellOneEndX, y:cellOneEndY})/segmentNumber; var facets = veinseed < 0.5 ? 1 : 0; // veins = 1, none = 0 if (facets == 1){ var pattern=context.createPattern(document.getElementById("noise_canvas"),"repeat"); context.rect(0,0,noise_canvas.width,noise_canvas.height); }else {pattern = 0.5} console.log(facets); console.log(veinseed); var endCells = scale; context.globalAlpha = veinseed*0.2 * facets; context.globalCompositeOperation = veinseed < 0.5 ? "screen" : "multiply"; //context.globalCompositeOperation = "multiply"; context.strokeStyle=pattern; context.setLineDash([Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9,Math.random()*9]) context.lineCap="round"; context.lineWidth=veinseed*4; context.scale(0.8,1.2); // quadratic bezier: percent is 0-1 function getQuadX(startPoint,controlPoint,endPoint,percent) { var x = Math.pow(1-percent,2) * startPoint + 2 * (1-percent) * percent * controlPoint + Math.pow(percent,2) * endPoint; return x; } function getQuadY(startPoint,controlPoint,endPoint,percent) { var y = Math.pow(1-percent,2) * startPoint + 2 * (1-percent) * percent * controlPoint + Math.pow(percent,2) * endPoint; return y; } context.beginPath(); context.moveTo(cellOneStartX, cellOneStartY); context.quadraticCurveTo(cellOneControlX, cellOneControlY, cellOneEndX, cellOneEndY); context.moveTo(cellOneStartX, cellOneStartY); context.quadraticCurveTo(cellOneControlY, cellOneControlX, cellOneEndX, cellOneEndY); context.stroke(); context.save(); context.globalAlpha= veinseed*0.07; context.globalCompositeOperation = "overlay"; context.fillStyle= 'white'; //chage to gradient probably context.fill(); context.restore(); context.closePath(); for (i = 0; i < mothCells; i++){ context.beginPath(); var curveToX = cellOneStartX/2 + cellOneEndX; var curveToY = cellOneStartY/2 + cellOneEndY/6; //othercells context.moveTo(getQuadX(cellOneStartX, cellOneControlX, cellOneEndX, i/mothCells), getQuadY(cellOneStartY, cellOneControlY, cellOneEndY, i/mothCells)); context.quadraticCurveTo(curveToX + i * segmentNumber, curveToY + i * segmentNumber, cellOneStartX + endCells + i * segmentNumber, cellOneStartY + endCells + i * segmentNumber); context.moveTo(getQuadX(cellOneStartX, cellOneControlX, cellOneEndX, i/mothCells), getQuadY(cellOneStartY, cellOneControlY, cellOneEndY, i/mothCells)); context.quadraticCurveTo(curveToY + i * segmentNumber, curveToX + i * segmentNumber, cellOneStartX + endCells + i * segmentNumber, cellOneStartY + endCells + i * segmentNumber); var mothCells2 = quadraticBezierLength({x:getQuadX(cellOneStartX, cellOneControlX, cellOneEndX, i/mothCells), y:getQuadY(cellOneStartY, cellOneControlY, cellOneEndY, i/mothCells)}, {x:cellOneControlX + i, y:cellOneControlY + i}, {x:cellOneEndX +i , y:cellOneEndY + i})/segmentNumber; context.globalAlpha = veinseed*0.2 * facets; context.stroke(); context.save(); context.globalAlpha= veinseed*0.01; context.globalCompositeOperation = "overlay"; context.fillStyle= 'white'; //chage to gradient probably context.fill(); context.restore(); if (i==0 && veinseed * 3 < 1){ // need better deterministic spot seed also colors context.save(); context.clip(); spots(veinseed*(curveToX/4) + cellOneControlX, veinseed*(curveToY/4) + cellOneControlY, veinseed*80 +20, veinseed*100); context.restore(); } context.closePath(); for ( n = 0; n < mothCells2; n++){ context.beginPath(); var nMoveToX = getQuadX(getQuadX(cellOneStartX, cellOneControlX, cellOneEndX, i/mothCells), curveToX + i * segmentNumber, cellOneStartX + endCells + i * segmentNumber + n, n/mothCells2); var nMoveToY = getQuadY(getQuadY(cellOneStartY, cellOneControlY, cellOneEndY, i/mothCells), curveToY + i * segmentNumber, cellOneStartY + endCells + i * segmentNumber + n, n/mothCells2); context.moveTo(nMoveToX, nMoveToY); context.quadraticCurveTo(cellOneControlX/mothCells2 + i * segmentNumber + n * segmentNumber, cellOneControlY/mothCells2 + i * segmentNumber+ n * segmentNumber, cellOneStartX + endCells + n * segmentNumber + i * segmentNumber, cellOneStartY + veinseed*endCells - i * n); context.moveTo(nMoveToX, nMoveToY); context.quadraticCurveTo(cellOneControlY/mothCells2 + i * segmentNumber + n * segmentNumber +100, cellOneControlX/mothCells2 + i * segmentNumber + n * segmentNumber +100, cellOneStartY + veinseed*endCells - i * n, cellOneStartX + endCells + n * segmentNumber + i * segmentNumber); context.globalAlpha = veinseed*0.2 * facets; context.stroke(); context.save(); context.globalAlpha= veinseed*0.02; context.globalCompositeOperation = "overlay"; context.fillStyle= 'white'; //chage to gradient probably context.fill(); context.restore(); /* //this is where i stopped context.save(); context.clip(); context.globalCompositeOperation = "overlay"; context.lineCap="round"; context.lineWidth=1; context.globalAlpha= 1; context.strokeStyle = pattern; context.moveTo(nMoveToX, nMoveToY); //context.stroke(); context.restore(); */ context.closePath(); } //console.log (getQuadX(cellOneStartX, cellOneControlX, cellOneEndX, 0.5)); //console.log (getQuadY(cellOneStartY, cellOneControlY, cellOneEndY, 0.5)); } context.restore(); }