An Introduction to css-doodle
Yuan Chuan
How it begins
<div class="grid">
<div class="cell">
<div class="cell">
<div class="cell">
<div class="cell">
<!-- ... -->
</div>
<style>
.cell:nth-child(1) { /* ... */ }
.cell:nth-child(2) { /* ... */ }
.cell:nth-child(3) { /* ... */ }
.cell:nth-child(4) { /* ... */ }
<!-- ... -->
</style>
<x-pattern>
_.backgroundColor = color();
_.borderRadius = rand(
'100% 0 0 0',
'0 100% 0 0',
'0 0 100% 0',
'0 0 0 100%'
);
</x-pattern>
<css-doodle>
@grid: 6x5 / 37vw auto / #f5f5f5;
background: @p(
#252386, #C92995, #91228C, #4C1981
);
border-radius: @p.cycle(
100% 0 0 0
);
</css-doodle>
<css-doodle>
@grid: 6x5 / 37vw auto / #f5f5f5;
background: @p(
#252386, #C92995, #91228C, #4C1981
);
clip-path: circle(
100% at @M2.p(0, 100%)
);
</css-doodle>
<css-doodle>
@grid: 6x5 / 37vw auto / #f5f5f5;
background: radial-gradient(
@p(#252386, #C92995, #91228C, #4C1981)
70.7%, #0000 0
);
background-size: 200% 200%;
background-position: @M2.p(-100%, 0);
</css-doodle>
css-doodle doesn't have a real
CSS parser
selector {
property: value;
}
Selector
@col {}
@row {}
@at {}
@nth {}
@even {}
@odd {}
@random {}
@match {}
@hover {}
Property
@grid
@seed
@gap
@size
@place
@use
@shape
@content
Value
@i, @I, @x, @y, @X, @Y
@m, @M, @n, @nx, @ny, @N
@p, @P, @pl, @pr, @pd, @lp,
@r, @rn, @lr,
@svg, @svg-polygon,
@doodle, @shaders, @pattern
@mirror, @cycle, @reverse,
@plot, @shape
...
@grid: 5 / 32vw;
@content: @i;
@odd {
background: #000;
color: #fff;
}
@nth(13) {
background: red;
@shape: star;
}
@grid: 10 / 32vw no-clip; background: #000; margin: auto; @size: calc(@i * 1%); rotate: calc(360deg / @I * @i);
@grid: 10 / 32vw no-clip; background: #000; margin: auto;@size: calc(@i * 1%);@size: @i(*1%);rotate: calc(360deg / @I * @i);rotate: @iI(*360deg);
@size: calc(@i * 1%);
@size: @i(*1%);
rotate: calc(360deg / @I * @i);
rotate: @iI(*360deg);
Function syntax
@i
@i()
@i(5)
@i(*10)
@i(10/)
@i(*10, -2, 48/)
calc(48 / (@i * 10 - 2))
@r
@r(1)
@r(0, 1)
@r255
@r.@r255
@r.r.r.r.r255
@r(@r(@r(@r(@r(255)))))
@grid: 2000x1 / 32vw; @place: center; @size: 4px; border-radius: 50%; background: #000; --d: 1 - @r.r.r.r; translate: $vw(15d * @cos.iI(*2π)) $vw(15d * @sin.iI(*2π))
Random functions
@pick, @p @P @pl, @pn @pr, @pnr @pd
@p(1,2,3,4,5)
@p([1-5])
@P([1-5])
@pd([1-5])
@pl([1-5]) / @pn([1-5])
@pr([1-5])
@grid: 3x6 / 50vw auto; --mode: @pl( normal, multiply, screen, overlay, darken, lighten, color-dodge, color-burn, hard-light, soft-light, difference, exclusion, hue, saturation, color, luminosity, plus-darker, plus-lighter ); background: @doodle( @grid: 3x1; mix-blend-mode: @p(--mode); border-radius: 50%; background: @pl(red, blue, yellow); @place: @plot(r: .25); @size: 40%; ); @content: @p(--mode); place-content: end center; font-size: .5em;
@r, @R, @rn
scale: @r(0, 1); rotate: @r(0, 1turn);
scale: @R(0, 1); rotate: @R(0, 1turn);
scale: @R(0, 1, 3); rotate: @R(0, 1turn, 3);
@grid: 24 / 61.8vh 80vh / #f1fbff;
@seed: 1718264392842;
scale: @R(0, 2, 2);
rotate: @R(±30deg, 2);
--c: @p(#155674,#60beb3,#79f8bb,#f5ffae);
:after {
content: @p('⬮', '.');
z-index: 1;
position: absolute;
font-size: @R(4vmin);
line-height: 0;
color: @p(--c);
scale: @R(.1, 2);
text-shadow: @m2(@M2.r(±2vmin) 0 @p(--c));
}
@random(.05) {
:after { color: #ff0000 }
}
@random(.3) {
rotate: @R(±90deg, 2);
:after {
z-index: 0;
@size: 1px @R(0, 30px, 3);
background: linear-gradient(@p(--c) @R(50%), #0000);
}
}
@random(.1) {
:before {
content: '.';
position: absolute;
color: @p(--color);
opacity: @R1;
text-shadow: @m24(@plot(r: @R(3em)) 0 currentColor);
}
}
Random seed
<css-doodle seed="anything"> @seed: anything; /* ... */ </css-doodle>
generator functions
@m @M @rep @mirror @Mirror @cycle @reverse
@m(10, 0)
@m10(0)
@M10(0)
@M10(@n)
@M10.n
@M12-2.n
@mirror.m5.n
@Mirror.m5.n
@cycle.m5.n
@grid: 1 / 75vh;
background: @m100(
conic-gradient(
from @pd(±15, ±30, ±45, ±60, ±90)deg,
@m100(red, blue, yellow)
)
@pl(0%, 100%) 100% / 2000% 2000%
no-repeat
);
background-blend-mode: difference;
filter: invert(1) hue-rotate(220deg);
background functions
background: @doodle() background: @shaders() background: @pattern() background: @svg() background: @svg-polygon()background: @canvas()
CSS background is like a mirror or a digital screen, everything inside it is virtual and untouchable since there's no actual DOM inside there. But it gives us a window for imagination and a bridge to connect other things.
background: @doodle( @grid: 2x2; background: @p(red, blue); )
@grid: @p(4, 5) / 75vh _1px;
--c: #FDF9EB, #BADFDB, #4ABFB8, #FF8B5C,
#E63946, #F1FAEE, #A8DADC, #457B9D;
background: @p(@p(--c), @m2.doodle(
@grid: @r4 _1px;
background: @p(@p(--c), @m3.doodle(
@grid: @r4 _1px;
background: @p(@p(--c), @m2.doodle(
@grid: @r4 _1px;
background: @p(--c);
))
))
))
@grid: 1 / 60vmin;
background: @shaders(
void main() {
vec2 p = gl_FragCoord.xy / u_resolution.xy;
FragColor = vec4(p.xy, .8, 1.);
}
)
@grid: 1 / 75vh;
background: @pattern(
grid: 71;
fill: #333;
match(((int(x*y*x*y*7.)>>4)&2) == 2) {
fill: #fff;
}
)
@grid: 1 / 75vh / #283944;
--c: #fff, #fb56ce, #88ffea, #ffd52d, #65b5b5;
background: @svg(
viewBox: -50 -50 100 100;
circle*20 {
r: @nN(*30, 4);
fill: none;
stroke: @p(--c);
stroke-linecap: round;
stroke-width: @r(.5, 1.5);
stroke-dasharray: @nN(*90, 10);
transform: rotate(@nN(* -720));
}
)
Experimenting A New Syntax To Write SVG
https://yuanchuan.dev/experimenting-a-new-syntax-to-write-svg
Shapes
@shape: heart; /* or */ clip-path: @shape(heart);
clip-path: @shape(
fill:nonzero | evenodd;
frame:number for frame size;
points:number between 3 - 3600;
rotate:number in degree for rotation;
scale:number for scale factor;
move:a pair of value for translating x, y coords;
turn:angle between start/end point, defaults to be 1;
x:x coordinate for cartesian equation;
y:y coordinate for cartesian equation;
r:polar equation;
)
points: 360; scale: .5; x: cos(2t) + cos(7t); y: sin(2t) + sin(7t); fill: evenodd;
points: 360; scale: .49; x: sin(5t) + sin(4t); -y: cos(4t) + cos(10t);
points: 1000; scale: .061 .06; x: (11*cos(.6t) + cos(55t) - 2.8) * -1.81; -y: (11*sin(9.03t) - sin(77t)) * 2.5 + 17;
points: 480; scale: .3; move: 0 .35; x: sin(t) + sin(6t) + tan.sin(2t); y: cos(t) + cos(5t) + tan.cos(8t);
Playground
Notes about shapes
@grid: 1 / 70vh border; background: #000; clip-path: @shape( points: 1000; scale: .8; move: .5 .64; x: cos(t^t) + cos(1.8^t); y: sin(t) + sin(2.305t)*sin(t); )
Documentation
CodePen collection