From 0a0a761e235253154c21006cace0da9a6748ffd2 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 19 Jan 2023 11:59:43 +0100 Subject: [PATCH 1/2] rename a to angle --- packages/core/animate.mjs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/core/animate.mjs b/packages/core/animate.mjs index 4ebb71ff..80e8501b 100644 --- a/packages/core/animate.mjs +++ b/packages/core/animate.mjs @@ -22,11 +22,11 @@ Pattern.prototype.animate = function ({ callback, sync = false, smear = 0.5 } = ctx.fillStyle = clearColor; ctx.fillRect(0, 0, ww, wh); frame.forEach((f) => { - let { x, y, w, h, s, r, a = 0, fill = 'darkseagreen' } = f.value; + let { x, y, w, h, s, r, angle = 0, fill = 'darkseagreen' } = f.value; w *= ww; h *= wh; - if (r !== undefined && a !== undefined) { - const radians = a * 2 * Math.PI; + if (r !== undefined && angle !== undefined) { + const radians = angle * 2 * Math.PI; const [cx, cy] = [(ww - w) / 2, (wh - h) / 2]; x = cx + Math.cos(radians) * r * cx; y = cy + Math.sin(radians) * r * cy; @@ -51,7 +51,7 @@ Pattern.prototype.animate = function ({ callback, sync = false, smear = 0.5 } = return silence; }; -export const { x, y, w, h, a, r, fill, smear } = createParams('x', 'y', 'w', 'h', 'a', 'r', 'fill', 'smear'); +export const { x, y, w, h, angle, r, fill, smear } = createParams('x', 'y', 'w', 'h', 'angle', 'r', 'fill', 'smear'); export const rescale = register('rescale', function (f, pat) { return pat.mul(x(f).w(f).y(f).h(f)); From ba6714f384e3064605375add72ca3859c8d321d6 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 19 Jan 2023 12:00:00 +0100 Subject: [PATCH 2/2] add draw examples --- website/src/repl/drawings.mjs | 172 ++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 website/src/repl/drawings.mjs diff --git a/website/src/repl/drawings.mjs b/website/src/repl/drawings.mjs new file mode 100644 index 00000000..0aa09ef3 --- /dev/null +++ b/website/src/repl/drawings.mjs @@ -0,0 +1,172 @@ +export const lightflower = `Pattern.prototype.nest = function(n, cycles) { + n = reify(n) + return this.echo(n, pure(cycles).div(n), 1) +} + +Pattern.prototype.deepimpose = function(func, times) { + if(times===0) return this; + return this.superimpose(x=>func(x).deepimpose(func, times-1)) +} + +angle(saw) + .fill('#aaffee12') + .r(.18) + .w(.06) + .h(.06) + .deepimpose(x=>x.mul(r(2).w(2).h(2)).late(1/12), 3) + .nest(6, 1) + .s('ellipse') + .mul(w(sine).h(sine).range(.5,1.25)) + .off(.5, x=>x.fill('#ffeeaa12').rev().div(r(1.2))) + .slow(16) + .smear(0.6) + .animate({smear:0}) +`; + +// https://strudel.tidalcycles.org/?C31_NrcMfZEO +export const spiralflower = `const {innerWidth:ww,innerHeight:wh} = window; +const ctx = getDrawContext() +const piDiv180 = Math.PI / 180; +function fromPolar(angle, radius, cx, cy) { + const radians = (angle-90) * piDiv180 + return [cx + Math.cos(radians) * radius, cy + Math.sin(radians) * radius] +} +const [w, h] = [200,200] +const [cx,cy] = [ww/2,wh/2]; +function drawSpiralSegment(ctx, {angle,b,r, density = 2, color = 'darkseagreen', thick = 2, long = 1}) { + let i = angle; + ctx.beginPath(); + while(i < b){ + const radius = Math.max(Math.min(r - i*.2,1000),20); + const [x1,y1] = fromPolar(i, radius, cx, cy) + const [x2,y2] = fromPolar(i, radius+long, cx, cy) + ctx.lineWidth = thick; + ctx.moveTo(x1,y1); + ctx.strokeStyle= color + ctx.lineTo(x2,y2); + ctx.stroke() + i+=300/density; + } +} +const { r, angle, b, color, density,thick} = + createParams('r', 'angle', 'b', 'color','density','thick','long'); + + +const pattern = + r(sine.range(200,800).slow(4)) + .angle(cosine.range(0, 45).slow(3)) + .b(perlin.range(1000, 4000).slow(5)) + .thick(sine.range(2,50).slow(2)) + .long(perlin.range(1,100).slow(3)) + .off(1, x=>x.color('white')) + .off(2, x=>x.color('salmon')) + .off(4, x=>x.color('purple')) + .slow(4)//.mask("x(5,8)") + + +function onDraw(f) { + ctx.beginPath(); + drawSpiralSegment(ctx, f.value); +} + + +// generic draw logic +window.frame && cancelAnimationFrame(window.frame); + +function render(t) { + t = Math.round(t) + const frame = pattern.slow(1000).queryArc(t, t) + ctx.fillStyle='#20001005' + ctx.fillRect(0,0,ww,wh) + //ctx.clearRect(0,0,ww,wh) + ctx.stroke() + frame.forEach(onDraw) + window.frame = requestAnimationFrame(render); +}; + +window.frame = requestAnimationFrame(render); + +silence +`; + +export const syncexample = `"<0 1 2 3>/2" +.off(1/2, add(4)) +.off(1, add(2)) +.scale(cat('C minor','C major').slow(8)) +.layer( + x=>x.note().piano(), + p=>stack( + p + .angle(p.sub('c3').div(12)) + .r(.5) + .s('ellipse') + .w(.1) + .h(.1), + p.x(p.sub('c3').div(12)) + .y(.9) + .w(1/12) + .h(.1) + .s('rect') + ).animate({sync:true,smear:0.9}) +) +`; + +export const moveRescaleZoom = ` +const rescale = register('rescale', function (f, pat) { + return pat.mul(x(f).w(f).y(f).h(f)); +}) + +const move = register('move', function (dx, dy, pat) { + return pat.add(x(dx).y(dy)); +}) + +const zoom = register('zoom', function (f, pat) { + const d = pure(1).sub(f).div(2); + return pat.rescale(f).move(d, d); +}) + +x(.5).y(.5).w(1).h(1) + .zoom(saw.slow(3)) + .move(sine.range(-.1,.1),0) + .fill("#ffeeaa10") + .s('rect') + .echo(6,.5,1) + .animate({smear:0.5})`; + +export const strudelS = ` +const rescale = register('rescale', function (f, pat) { + return pat.mul(x(f).w(f).y(f).h(f)); +}) + +const move = register('move', function (dx, dy, pat) { + return pat.add(x(dx).y(dy)); +}) + +const flipY = register('flipY', function (pat) { + return pat.fmap(v => ({...v, y:1-v.y})) +}) + +const zoom = register('zoom', function (f, pat) { + const d = pure(1).sub(f).div(2); + return pat.rescale(f).move(d, d); +}) + +Pattern.prototype.nest = function(n, cycles) { + n = reify(n) + return this.echo(n, pure(cycles).div(n), 1) +} + +x(sine.div(1)).y(cosine.range(0,.5)) + .w(.1).h(.1) + .mul(w(square).h(square).slow(8)) + .zoom(saw.slow(8)) + .layer( + id, + _=>_.flipY().move(0,0).rev() + ) + .mask("0 1@2").rev() + .nest(16,9) + .s('rect') + .fill("royalblue steelblue".fast(14)) + .slow(8) + .animate({smear:.99})`;