Emoji Style Faces with SVG.js
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:
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()
}