Emoji Style Faces with SVG.js 2019-04-19 I tried and failed to get ‘svg.js’ to work with TypeScript, despite it having a ‘svg.js.d.ts’ file. So, I switched to vanilla JavaScript. My inspiration for this Emoji guy was from watching this YouTube video: Making a smiley in ShaderToy by The Art of Code Reload to see more random faces. faces.js import * as SVG from 'svg.js'; class Face { constructor() { let size = 144 this.draw = SVG('drawing').size(size, size) let faceWidth = size * this.randomRange(0.6, 0.8) let faceHeight = size * this.randomRange(0.6, 0.9) let xOffset = size / 2 - faceWidth / 2 let yOffset = size / 2 - faceHeight / 2 let earWidth = faceWidth / this.randomRange(4.5, 5.5) let earHeight = faceHeight / this.randomRange(4.5, 5.5) this.draw.ellipse(earWidth, earHeight).fill(this.faceGradient()).move(xOffset + faceWidth - earWidth/2, yOffset + faceHeight / 2.2) this.draw.ellipse(earWidth, earHeight).fill(this.faceGradient()).move(xOffset - earWidth/2, yOffset + faceHeight / 2.2) this.draw.ellipse(faceWidth, faceHeight).fill(this.faceGradient()).move(xOffset, yOffset) let xOffset2 = size / 2 - faceWidth * 0.9 / 2 let yOffset2 = size / 2 - faceHeight * 0.9 / 2 this.draw.ellipse(faceWidth * 0.9, faceHeight * 0.9).fill(this.reflectFaceGradient2()).move(xOffset2, yOffset2) xOffset2 = size / 2 - faceWidth * 0.89 / 2 yOffset2 = size / 2 - faceHeight * 0.89 / 2 this.draw.ellipse(faceWidth * 0.89, faceHeight * 0.89).fill(this.reflectFaceGradient()).move(xOffset2, yOffset2) let eyeWidth = faceWidth / this.randomRange(3, 5.5) let eyeHeight = faceHeight / this.randomRange(4.5, 5.5) let eyeDistance = eyeWidth * this.randomRange(0.25, 0.75) let browAngle = this.randomRange(-10, 10) let browOffset = this.randomRange(1.4, 2.2) let browHeight = this.randomRange(0.4, 0.7) let pupilSize = this.randomRange(0.3, 0.6) let pupilXoffset = this.randomRange(-0.3, 0.3) let pupilYoffset = this.randomRange(-0.3, 0.3) let eyeShapeWidth = this.randomRange(1.0, 1.2) let eyeShapeHeight = this.randomRange(0.3, 0.7) let eyeRotation = this.randomRange(-10, 10) this.eye({ eyeWidth: eyeWidth, eyeHeight: eyeHeight, xPos: xOffset + faceWidth / 2 - eyeDistance / 2 - eyeWidth, yPos: yOffset + faceHeight / 2 - eyeHeight / 2, orientation: -1, browAngle: browAngle, pupilSize: pupilSize, browOffset: browOffset, browHeight: browHeight, pupilXoffset: pupilXoffset, pupilYoffset: pupilYoffset, eyeShapeWidth: eyeShapeWidth, eyeShapeHeight: eyeShapeHeight, eyeRotation: eyeRotation }) this.eye({ eyeWidth: eyeWidth, eyeHeight: eyeHeight, xPos: xOffset + faceWidth / 2 + eyeDistance / 2, yPos: yOffset + faceHeight / 2 - eyeHeight / 2, orientation: 1, browAngle: browAngle, pupilSize: pupilSize, browOffset: browOffset, browHeight: browHeight, pupilXoffset: pupilXoffset, pupilYoffset: pupilYoffset, eyeShapeWidth: eyeShapeWidth, eyeShapeHeight: eyeShapeHeight, eyeRotation: eyeRotation }) let cheekWidth = faceWidth / 3.5 let cheekHeight = faceHeight / 3.5 let faceMask = this.draw.ellipse(faceWidth, faceHeight).fill("white").move(xOffset, yOffset) this.draw.ellipse(cheekWidth, cheekHeight).fill(this.redGradient()).move(xOffset + faceWidth - cheekWidth - cheekWidth / 4 , yOffset + faceHeight / 1.7).maskWith(faceMask) let faceMask2 = this.draw.ellipse(faceWidth, faceHeight).fill("white").move(xOffset, yOffset) this.draw.ellipse(cheekWidth, cheekHeight).fill(this.redGradient()).move(xOffset + cheekWidth / 4, yOffset + faceHeight / 1.7).maskWith(faceMask2) let mouthWidth = faceWidth / this.randomRange(2.0, 3.0) let mouthHeight = faceHeight / this.randomRange(8.0, 11.0) let mouthOffset = this.randomRange(18, 22) let mouthPosOffset = this.randomRange(-0.2, 0.6) * (faceHeight * 0.15) let group = this.draw.group() let mouth = group.ellipse(mouthWidth, mouthHeight).fill('white').move(xOffset + faceWidth / 2 - mouthWidth/2, mouthPosOffset + yOffset + faceHeight / 2 + faceHeight / 4) mouthWidth = faceWidth / this.randomRange(2.0, 3.0) group.ellipse(mouthWidth, mouthHeight).fill(this.mouthGradient()).move(xOffset + faceWidth / 2 - mouthWidth/2, mouthPosOffset + yOffset + faceHeight / 2 + faceHeight / 4 - faceHeight / mouthOffset).maskWith(mouth) group.rotate(this.randomRange(-8, 8)) //mustache // if (Math.random() < 0.35) { // let hairWidth = faceWidth * 0.01 // let hairHeight = faceHeight * this.randomRange(0.05, 0.15) // for (var angle = -40; angle < 40; angle += 5) { // this.draw.rect(hairWidth, hairHeight).fill('#6b5f0a').translate(xOffset + faceWidth / 2, yOffset + faceHeight / 2.2).rotate(angle).move(0, (faceHeight / 4)) // } // } //beard if (Math.random() < 0.35) { let hairHeight = faceHeight * this.randomRange(0.1, 0.2) let hairWidth = faceWidth * 0.01 for (var angle = -30; angle < 30; angle += 3) { this.draw.rect(hairWidth, hairHeight).fill('#6b5f0a').translate(xOffset + faceWidth / 2 - hairWidth / 2, yOffset + faceHeight / 2.2).rotate(angle).move(0, (faceHeight / 2.2)) } } //hair // if (Math.random() < 0.35) { // let hairHeight = faceHeight * this.randomRange(0.1, 0.3) // let hairWidth = faceWidth * 0.01 // for (var angle = -60; angle < 60; angle += 3) { // this.draw.rect(hairWidth, hairHeight).fill('#6b5f0a').translate(xOffset + faceWidth / 2 - hairWidth / 2, yOffset + faceHeight / 2.2).rotate(angle).move(0, -(faceHeight / 1.8)) // } // } let noseWidth = faceWidth / this.randomRange(3.5, 4.5) let noseHeight = faceHeight / this.randomRange(5.5, 6.5) this.draw.ellipse(noseWidth, noseHeight).fill(this.lightFaceGradient()).move(xOffset + faceWidth / 2 - noseWidth/2, yOffset + faceHeight / 1.8) // // mouthWidth = faceWidth / 2 // mouth = this.draw.ellipse(mouthWidth, mouthHeight).fill('white').move(xOffset + faceWidth / 2 - mouthWidth/2, yOffset + faceHeight / 2 + faceHeight / 4) // mouthWidth = faceWidth / 1.6 // this.draw.ellipse(mouthWidth, mouthHeight).fill(this.eyeGradient()).move(xOffset + faceWidth / 2 - mouthWidth/2, yOffset + faceHeight / 2 + faceHeight / 4 - faceHeight / 15).maskWith(mouth) } mouthGradient() { return this.draw.gradient('linear', function(stop) { stop.at(0, "#93671c") stop.at(1, "#C3972c") }).from(0, 0).to(0, 1) } reflectFaceGradient2() { return this.draw.gradient('linear', function(stop) { stop.at(0, "rgba(255, 255, 255, 0.6)") stop.at(0.25, "rgba(255, 255, 255, 0.0)") stop.at(1, "rgba(255, 255, 255, 0.0)") }).from(0, 0).to(0, 1) } reflectFaceGradient() { return this.draw.gradient('linear', function(stop) { stop.at(0, "rgba(255, 255, 255, 0.4)") stop.at(0.25, "rgba(255, 255, 255, 0.0)") stop.at(1, "rgba(255, 255, 255, 0.0)") }).from(0, 0).to(0, 1) } redGradient() { return this.draw.gradient('radial', function(stop) { stop.at(0, "rgba(255, 100, 0, 0.4)") stop.at(1, "rgba(255, 100, 0, 0.0)") }) } faceGradient() { return this.draw.gradient('radial', function(stop) { stop.at(0, '#fff944') stop.at(0.8, '#e0bc38') stop.at(1, '#b28229') }) } lightFaceGradient() { return this.draw.gradient('radial', function(stop) { stop.at(0, '#ffe944') stop.at(1, '#d8bc38') }) } eyeGradient() { return this.draw.gradient('radial', function(stop) { stop.at(0, '#ffffff') stop.at(1, '#dddddd') }) } eye(params) { let eyeWidth = params["eyeWidth"] let eyeHeight = params["eyeHeight"] let xPos = params["xPos"] let yPos = params["yPos"] let pupilSizeScale = params["pupilSize"] let orientation = params["orientation"] let browAngle = params["browAngle"] let browOffset = params["browOffset"] let browHeight = params["browHeight"] let pupilXoffset = params["pupilXoffset"] let pupilYoffset = params["pupilYoffset"] let eyeShapeWidthFactor = params["eyeShapeWidth"] let eyeShapeHeightFactor = params["eyeShapeHeight"] let eyeRotation = params["eyeRotation"] let pupilSize = Math.min(eyeWidth, eyeHeight) * pupilSizeScale let shineSize = pupilSize * 0.4 let eyeShapeWidth = eyeWidth * eyeShapeWidthFactor let eyeShapeHeight = eyeHeight * eyeShapeHeightFactor let eyeXOffset = eyeShapeWidth / 2 - eyeWidth / 2 let eyeYOffset = eyeShapeHeight / 2 - eyeHeight / 2 this.draw.ellipse(eyeWidth, eyeHeight).fill(this.lightFaceGradient()).move(xPos, yPos) let eyeShape = this.draw.ellipse(eyeShapeWidth, eyeShapeHeight).fill('white').move(xPos-eyeXOffset, yPos-eyeYOffset)//.rotate(eyeRotation * orientation) this.draw.ellipse(eyeWidth, eyeHeight).fill(this.eyeGradient()).move(xPos, yPos).maskWith(eyeShape) eyeShape = this.draw.ellipse(eyeShapeWidth, eyeShapeHeight).fill('white').move(xPos-eyeXOffset, yPos-eyeYOffset)//.rotate(eyeRotation * orientation) this.draw.ellipse(pupilSize, pupilSize).fill('black').move(xPos+eyeWidth/2-pupilSize/2 + pupilXoffset * pupilSize, yPos+eyeHeight/2-pupilSize/2+ pupilYoffset * pupilSize).maskWith(eyeShape) eyeShape = this.draw.ellipse(eyeShapeWidth, eyeShapeHeight).fill('white').move(xPos-eyeXOffset, yPos-eyeYOffset)//.rotate(eyeRotation * orientation) this.draw.ellipse(shineSize, shineSize).fill('white').move(xPos+eyeWidth/2-pupilSize/2+shineSize/2, yPos+eyeHeight/2-pupilSize/2).maskWith(eyeShape) let browShape = this.draw.rect(eyeShapeWidth, eyeShapeHeight * browHeight).fill('#6b5f0a').move(xPos-eyeXOffset, yPos - eyeYOffset - eyeHeight / browOffset).rotate(browAngle * orientation) } randomRange(start, end) { return Math.random() * (end-start) + start } } for (var i = 0; i < 16 ;i++) { new Face() } javascript svg.js