shithub: scrax

ref: 81d1e4e01d7001e6a0107792e6167136787295d6
dir: /worklet.js/

View raw version
class StackBlockPaint {
	
	static inputProperties = ["--color", "font-size", "--hat", "--cap", "--mouth-above", "--mouth-below", "--define"]
	
	paint(ctx, {width, height}, properties)
	{
		let isHat = properties.get("--hat")?.[0]
		let isCap = properties.get("--cap")?.[0]
		let isDefine = properties.get("--define")?.[0]
		let hasMouthAbove = properties.get("--mouth-above")?.[0]
		let hasMouthBelow = properties.get("--mouth-below")?.[0]
		let color = String(properties.get("--color"))
		let darker = `oklab(from ${color} calc(l - 0.25) a b)`
		let size = Number(properties.get("font-size").to("px").value)
		
		let x0 = 0
		let y0 = 0
		let x1 = width
		let y1 = height + 2
		
		y1 -= size / 2
		if (isHat) y0 += size
		if (hasMouthAbove) y0 += size / 2 - 2
		
		function drawBlock1()
		{
			ctx.beginPath()
			drawBlock(ctx, x0, y0, x1, y1, size, {isHat, isCap, hasMouthBelow, hasMouthAbove, isDefine})
		}
		
		drawBlock1()
		ctx.clip()
		
		ctx.rect(0, 0, width, height)
		ctx.fillStyle = color
		ctx.fill()
		
		if (!hasMouthAbove) {
			let gradient = ctx.createLinearGradient(x0, y0, x0, y1)
			gradient.addColorStop(0, "#FFF4")
			gradient.addColorStop(0.75, "#FFF0")
			ctx.fillStyle = gradient
			ctx.fill()
		}
		
		if (hasMouthAbove && !hasMouthBelow) {
			let gradient = ctx.createLinearGradient(x0, y0, x0, y1)
			gradient.addColorStop(0.25, "#0000")
			gradient.addColorStop(1, "#0001")
			ctx.fillStyle = gradient
			ctx.fill()
		}
		
		drawBlock1()
		ctx.strokeStyle = darker
		ctx.lineWidth = 4
		ctx.stroke()
		
		if (isHat || isDefine) return
		
		let x2 = 2
		if (hasMouthAbove) x2 += size + 2
		
		let gradient = ctx.createLinearGradient(x0, y0, x0, y0 + 100)
		gradient.addColorStop(0.02, darker)
		gradient.addColorStop(size / 100, "#222")
		
		ctx.beginPath()
		ctx.moveTo(size * 3 + x2, 0)
		ctx.lineTo(size * 3 + x2, 2)
		drawKnub(ctx, size + x2, y0 + 2, size * 2.5 + x2 + 2, y0 + size / 2)
		ctx.lineTo(x0 + x2 + size, y0)
		ctx.fillStyle = gradient
		ctx.fill()
	}
}

class BooleanBlockPaint {
	
	static inputProperties = ["--color"]
	
	paint(ctx, {width, height}, properties)
	{
		let color = String(properties.get("--color"))
		let darker = `oklab(from ${color} calc(l - 0.25) a b)`
		
		ctx.moveTo(0, height / 2)
		ctx.lineTo(height / 2, 0)
		ctx.lineTo(width - height / 2, 0)
		ctx.lineTo(width, height / 2)
		ctx.lineTo(width - height / 2, height)
		ctx.lineTo(height / 2, height)
		ctx.closePath()
		
		ctx.clip()
		
		ctx.fillStyle = color
		ctx.fill()
		
		let gradient = ctx.createLinearGradient(0, 0, 0, height)
		gradient.addColorStop(0, "#FFF4")
		gradient.addColorStop(0.75, "#FFF0")
		ctx.fillStyle = gradient
		ctx.fill()
		
		ctx.strokeStyle = darker
		ctx.lineWidth = 4
		ctx.stroke()
	}
}

registerPaint("stack-block", StackBlockPaint)
registerPaint("boolean-block", BooleanBlockPaint)

function drawBlock(ctx, x0, y0, x1, y1, size, {isHat, isCap, hasMouthBelow, hasMouthAbove, isDefine})
{
	let x2 = 2
	if (hasMouthBelow) x2 += size + 2
	let radius = size / 2
	let radius2 = radius
	if (isDefine) radius2 += size
	if (isHat) {
		ctx.moveTo(x0, y0 + size / 2)
		ctx.quadraticCurveTo(x0, y0 - size, x0 + size * 3, y0 - size)
		ctx.bezierCurveTo(x0 + size * 5, y0 - size, x0 + size * 6, y0, x0 + size * 8, y0)
	}
	else {
		if (hasMouthAbove) {
			ctx.moveTo(x0, y0 - radius * 2)
			ctx.lineTo(x0 + size + 4, y0 - radius * 2)
			ctx.arcTo(x0 + size + 4, y0, x0 + size * 2, y0, radius / 1.25)
		}
		else {
			ctx.moveTo(x0, y0 + radius)
			ctx.arcTo(x0, y0, x0 + radius, y0, radius2)
		}
	}
	ctx.arcTo(x1, y0, x1, y1, radius2)
	ctx.arcTo(x1, y1, x0, y1, radius)
	if (!isCap) drawKnub(ctx, x0 + size + x2, y1, x0 + size * 2.5 + x2 + 2, y1 + size / 2 - 2)
	if (hasMouthBelow) {
		ctx.lineTo(x0 + size + radius / 1.25 + 4, y1)
		ctx.arcTo(x0 + size + 4, y1, x0 + size + 4, y1 + radius / 1.25, radius / 1.25)
		ctx.lineTo(x0 + size + 4, y1 + size)
		ctx.lineTo(x0, y1 + size)
	}
	else {
		ctx.arcTo(x0, y1, x0, y0, radius)
	}
	ctx.closePath()
}

function drawKnub(ctx, x0, y0, x1, y1)
{
	let radius = (y1 - y0) / 2
	x1 -= radius
	ctx.arcTo(x1 + radius, y0, x1, y1 - radius / 2, radius / 2)
	ctx.arcTo(x1, y1, x0, y1, radius * 1.5)
	ctx.arcTo(x0 + radius, y1, x0, y0, radius * 1.5)
	ctx.arcTo(x0, y0, x0 - radius / 2, y0, radius / 2)
}