ref: 81d1e4e01d7001e6a0107792e6167136787295d6
dir: /worklet.js/
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) }