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()
}