<div id="ccc"></div>
<div id="config">
<div class="config-wrap">
<label
id="line-width-label"
for="line-width"
>
Line width (1)
</label>
<input
type="range"
min="1"
max="20"
value="1"
id="line-width"
name="line-width"
/>
</div>
<div class="config-wrap">
<label
id="sides-count-label"
for="sides-count"
>
Sides Count (8)
</label>
<input
type="range"
min="2"
max="24"
step="1"
value="8"
id="sides-count"
name="sides-count"
/>
</div>
<div class="config-wrap">
<label
id="scale-label"
for="scale"
>
Scale (50)
</label>
<input
type="range"
min="1"
max="150"
step="1"
value="75"
id="scale"
name="scale"
/>
</div>
<div class="config-wrap">
<label
id="rotation-label"
for="rotation"
>
Rotation (0)
</label>
<input
type="range"
min="0"
max="360"
step="1"
value="0"
id="rotation"
name="rotation"
/>
</div>
<div class="config-wrap">
<label
id="stroke-color-label"
for="stroke-color"
>
Stroke Color (#2980b9)
</label>
<input
type="color"
min="1"
max="20"
step="1"
id="stroke-color"
name="stroke-color"
value="#2980b9"
/>
</div>
</div>
<script id="c" type="text/worklet">
const PAINTLET_NAME = 'loop'
class CSSPaintlet {
static get inputProperties() {
return [
`--${PAINTLET_NAME}-line-width`,
`--${PAINTLET_NAME}-stroke-color`,
`--${PAINTLET_NAME}-sides`,
`--${PAINTLET_NAME}-scale`,
`--${PAINTLET_NAME}-rotation`,
]
}
paint(ctx, paintSize, props, args) {
const lineWidth = Number(props.get(`--${PAINTLET_NAME}-line-width`))
const strokeColor = props.get(`--${PAINTLET_NAME}-stroke-color`)
const numSides = Number(props.get(`--${PAINTLET_NAME}-sides`))
const scale = Number(props.get(`--${PAINTLET_NAME}-scale`))
const rotation = Number(props.get(`--${PAINTLET_NAME}-rotation`))
const angle = Math.PI * 2 / numSides
const radius = paintSize.height / 2
ctx.save()
ctx.lineWidth = lineWidth
ctx.lineJoin = 'round'
ctx.lineCap = 'round'
ctx.strokeStyle = strokeColor
ctx.translate(paintSize.width / 2, paintSize.height / 2)
ctx.rotate(rotation * (Math.PI / 180))
ctx.scale(scale / 100, scale / 100)
ctx.moveTo(0, radius)
for (let i = 0; i < numSides; i++) {
const x = Math.sin(i * angle) * radius
const y = Math.cos(i * angle) * radius
for (let n = i; n < numSides; n++) {
const x2 = Math.sin(n * angle) * radius
const y2 = Math.cos(n * angle) * radius
ctx.lineTo(x, y)
ctx.lineTo(x2, y2);
}
}
ctx.closePath()
ctx.stroke()
ctx.restore()
}
}
registerPaint(PAINTLET_NAME, CSSPaintlet)
</script>
* {
margin: 0;
padding: 0;
font-family: Helvetica, sans-serif;
}
#ccc {
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
--loop-line-width: 1;
--loop-stroke-color: #2980b9;
--loop-sides: 8;
--loop-scale: 100;
--loop-rotation: 0;
background-image: paint(loop);
background-repeat: no-repeat;
background-size: cover;
}
#config {
position: fixed;
bottom: 0;
left: 0;
padding: 1rem;
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(3px);
box-sizing: border-box;
border-top-right-radius: 24px;
}
.config-wrap {
margin-bottom: 0.75rem;
color: rgba(0, 0, 0, 0.8);
}
label {
display: block;
font-size: 11px;
text-transform: uppercase;
margin-bottom: 0.5rem;
}
console.clear()
const paintletCode = document.getElementById('c')
;(async function() {
// ⚠️ Handle Firefox and Safari by importing a polyfill for CSS Pain
if (CSS['paintWorklet'] === undefined) {
await import('https://unpkg.com/css-paint-polyfill')
}
// Explicitly define our custom CSS variable
// Make sure that the browser treats it as a number
if ('registerProperty' in CSS) {
CSS.registerProperty({
name: '--loop-line-width',
syntax: '<number>',
inherits: false,
initialValue: 1
})
CSS.registerProperty({
name: '--loop-stroke-color',
syntax: '<color>',
inherits: false,
initialValue: '#2980b9'
})
CSS.registerProperty({
name: '--loop-sides',
syntax: '<number>',
inherits: false,
initialValue: 8
})
CSS.registerProperty({
name: '--loop-scale',
syntax: '<number>',
inherits: false,
initialValue: 100
})
CSS.registerProperty({
name: '--loop-rotation',
syntax: '<number>',
inherits: false,
initialValue: 0
})
}
const lineWidthInput = document.getElementById('line-width')
const sidesCountInput = document.getElementById('sides-count')
const scaleInput = document.getElementById('scale')
const rotationInput = document.getElementById('rotation')
const strokeInput = document.getElementById('stroke-color')
const lineWidthLabel = document.getElementById('line-width-label')
const sidesCountLabel = document.getElementById('sides-count-label')
const scaleLabel = document.getElementById('scale-label')
const rotationLabel = document.getElementById('rotation-label')
const strokeLabel = document.getElementById('color-color-label')
const workletElement = document.getElementById('ccc')
lineWidthInput.addEventListener('change', e => {
const lineWidth = Number(e.target.value)
lineWidthLabel.textContent = `Line width (${lineWidth})`
workletElement.style.setProperty('--loop-line-width', lineWidth)
})
sidesCountInput.addEventListener('change', e => {
const sidesCount = Number(e.target.value)
sidesCountLabel.textContent = `Sides Count (${sidesCount})`
workletElement.style.setProperty('--loop-sides', sidesCount)
})
scaleInput.addEventListener('change', e => {
const scale = Number(e.target.value)
scaleLabel.textContent = `Scale (${scale})`
workletElement.style.setProperty('--loop-scale', scale)
})
rotationInput.addEventListener('change', e => {
const rotation = Number(e.target.value)
rotationLabel.textContent = `Rotation (${rotation})`
workletElement.style.setProperty('--loop-rotation', rotation)
})
strokeInput.addEventListener('change', e => {
const strokeColor = e.target.value
rotationLabel.textContent = `Stroke Color (${strokeColor})`
workletElement.style.setProperty('--loop-stroke-color', strokeColor)
})
// Include our paintlet using
registerCSSPaintlet(paintletCode.textContent)
})()
function registerCSSPaintlet (sourceCode) { CSS.paintWorklet.addModule(`data:application/javascript;charset=utf8,${encodeURIComponent(sourceCode)}`)
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.