From 90fdc6f9f6db6c2ca6df6e182e2f4b9c5e8a8334 Mon Sep 17 00:00:00 2001 From: Ben Brooks Date: Thu, 30 Nov 2023 16:20:51 -0800 Subject: [PATCH 1/3] Break up effects into individual files --- src/Effects.js | 2390 ++----------------------------- src/effects/bloomingPetals.js | 58 + src/effects/bubbles.js | 41 + src/effects/circles.js | 22 + src/effects/clouds.js | 47 + src/effects/colorCycle.js | 14 + src/effects/colorLights.js | 46 + src/effects/confetti.js | 49 + src/effects/diamonds.js | 30 + src/effects/disco.js | 49 + src/effects/discoBall.js | 104 ++ src/effects/emojis.js | 96 ++ src/effects/explodingStars.js | 43 + src/effects/fireworks.js | 139 ++ src/effects/floatingRainbows.js | 58 + src/effects/flowers.js | 33 + src/effects/frostedGrid.js | 37 + src/effects/galaxy.js | 58 + src/effects/growingStars.js | 36 + src/effects/heartsColorful.js | 41 + src/effects/heartsRed.js | 40 + src/effects/higherPower.js | 76 + src/effects/kaleidoscope.js | 123 ++ src/effects/lasers.js | 59 + src/effects/musicNotes.js | 52 + src/effects/musicWave.js | 30 + src/effects/paintDrip.js | 102 ++ src/effects/pineapples.js | 50 + src/effects/pizzas.js | 49 + src/effects/quads.js | 60 + src/effects/rain.js | 33 + src/effects/rainbow.js | 42 + src/effects/rainingTacos.js | 58 + src/effects/ripples.js | 99 ++ src/effects/smileFace.js | 50 + src/effects/smilingPoop.js | 46 + src/effects/snowflakes.js | 43 + src/effects/sparkles.js | 43 + src/effects/spiral.js | 31 + src/effects/splatter.js | 57 + src/effects/spotlight.js | 50 + src/effects/squiggles.js | 37 + src/effects/starburst.js | 26 + src/effects/stars.js | 44 + src/effects/swirl.js | 25 + src/effects/text.js | 40 + 46 files changed, 2463 insertions(+), 2293 deletions(-) create mode 100644 src/effects/bloomingPetals.js create mode 100644 src/effects/bubbles.js create mode 100644 src/effects/circles.js create mode 100644 src/effects/clouds.js create mode 100644 src/effects/colorCycle.js create mode 100644 src/effects/colorLights.js create mode 100644 src/effects/confetti.js create mode 100644 src/effects/diamonds.js create mode 100644 src/effects/disco.js create mode 100644 src/effects/discoBall.js create mode 100644 src/effects/emojis.js create mode 100644 src/effects/explodingStars.js create mode 100644 src/effects/fireworks.js create mode 100644 src/effects/floatingRainbows.js create mode 100644 src/effects/flowers.js create mode 100644 src/effects/frostedGrid.js create mode 100644 src/effects/galaxy.js create mode 100644 src/effects/growingStars.js create mode 100644 src/effects/heartsColorful.js create mode 100644 src/effects/heartsRed.js create mode 100644 src/effects/higherPower.js create mode 100644 src/effects/kaleidoscope.js create mode 100644 src/effects/lasers.js create mode 100644 src/effects/musicNotes.js create mode 100644 src/effects/musicWave.js create mode 100644 src/effects/paintDrip.js create mode 100644 src/effects/pineapples.js create mode 100644 src/effects/pizzas.js create mode 100644 src/effects/quads.js create mode 100644 src/effects/rain.js create mode 100644 src/effects/rainbow.js create mode 100644 src/effects/rainingTacos.js create mode 100644 src/effects/ripples.js create mode 100644 src/effects/smileFace.js create mode 100644 src/effects/smilingPoop.js create mode 100644 src/effects/snowflakes.js create mode 100644 src/effects/sparkles.js create mode 100644 src/effects/spiral.js create mode 100644 src/effects/splatter.js create mode 100644 src/effects/spotlight.js create mode 100644 src/effects/squiggles.js create mode 100644 src/effects/starburst.js create mode 100644 src/effects/stars.js create mode 100644 src/effects/swirl.js create mode 100644 src/effects/text.js diff --git a/src/Effects.js b/src/Effects.js index bbaf584e..888b07e6 100644 --- a/src/Effects.js +++ b/src/Effects.js @@ -1,24 +1,52 @@ const constants = require('./constants'); -const drawFrostedGrid = require('./shapes/frostedGrid'); -const drawHeart = require('./shapes/heart'); -const drawLovestruck = require('./shapes/lovestruck'); -const drawMusicNote = require('./shapes/musicNote'); -const drawPetal = require('./shapes/petal'); -const drawPineapple = require('./shapes/pineapple'); -const drawPizza = require('./shapes/pizza'); -const drawPoop = require('./shapes/poop'); -const drawRainbow = require('./shapes/rainbow'); -const drawSmiley = require('./shapes/smiley'); -const drawSparkle = require('./shapes/sparkle'); -const drawSpiral = require('./shapes/spiral'); -const drawStar = require('./shapes/star'); -const drawStarburst = require('./shapes/starburst'); -const drawStarstruck = require('./shapes/starstruck'); -const drawSwirl = require('./shapes/swirl'); -const drawTaco = require('./shapes/taco'); -const drawTickled = require('./shapes/tickled'); -const drawWink = require('./shapes/wink'); -const {hexToRgb, getP5Color} = require('./utils'); + +const discoBall = require('./effects/discoBall'); +const higherPower = require('./effects/higherPower'); +const rainbow = require('./effects/rainbow'); +const flowers = require('./effects/flowers'); +const colorCycle = require('./effects/colorCycle'); +const disco = require('./effects/disco'); +const ripples = require('./effects/ripples'); +const bloomingPetals = require('./effects/bloomingPetals'); +const clouds = require('./effects/clouds'); +const frostedGrid = require('./effects/frostedGrid'); +const starburst = require('./effects/starburst'); +const diamonds = require('./effects/diamonds'); +const circles = require('./effects/circles'); +const sparkles = require('./effects/sparkles'); +const text = require('./effects/text'); +const splatter = require('./effects/splatter'); +const swirl = require('./effects/swirl'); +const spiral = require('./effects/spiral'); +const lasers = require('./effects/lasers'); +const quads = require('./effects/quads'); +const kaleidoscope = require('./effects/kaleidoscope'); +const snowflakes = require('./effects/snowflakes'); +const fireworks = require('./effects/fireworks'); +const stars = require('./effects/stars'); +const galaxy = require('./effects/galaxy'); +const growingStars = require('./effects/growingStars'); +const squiggles = require('./effects/squiggles'); +const musicWave = require('./effects/musicWave'); + +// foreground +const rain = require('./effects/rain'); +const rainingTacos = require('./effects/rainingTacos'); +const pineapples = require('./effects/pineapples'); +const spotlight = require('./effects/spotlight'); +const colorLights = require('./effects/colorLights'); +const smilingPoop = require('./effects/smilingPoop'); +const heartsRed = require('./effects/heartsRed'); +const heartsColorful = require('./effects/heartsColorful'); +const floatingRainbows = require('./effects/floatingRainbows'); +const bubbles = require('./effects/bubbles'); +const explodingStars = require('./effects/explodingStars'); +const pizzas = require('./effects/pizzas'); +const smileFace = require('./effects/smileFace'); +const confetti = require('./effects/confetti'); +const musicNotes = require('./effects/musicNotes'); +const paintDrip = require('./effects/paintDrip'); +const emojis = require('./effects/emojis'); module.exports = class Effects { constructor(p5, alpha, extraImages, blend, currentPalette = 'default') { @@ -80,2279 +108,55 @@ module.exports = class Effects { }, }; - this.disco_ball = { - stars: [], - globe: function (u, v) { - u = p5.constrain(u, -90, 90); - return { - x: (1 + p5.sin(u) * p5.sin(v)) * 45 + 155, - y: (1 + p5.cos(v)) * 45 + 10, - }; - }, - quad: function (i, j, faceSize, rotation = 0) { - const k = ((i + rotation) % 360) - 180; - if (k < -90 - faceSize || k > 90) { - return; - } - const color = lerpColorFromPalette(p5.noise(i, j, p5.frameCount / 70)); - const highlight = 50 * p5.pow(p5.cos(k), 2); - const brightness = - p5.noise(i, j, p5.frameCount / 50) * 150 + 100 + highlight; - p5.fill(p5.lerpColor(color, p5.color(brightness), brightness / 255)); - const a = this.globe(k, j); - const b = this.globe(k + faceSize, j); - const c = this.globe(k + faceSize, j + faceSize); - const d = this.globe(k, j + faceSize); - p5.quad(a.x, a.y, b.x, b.y, c.x, c.y, d.x, d.y); - }, - init: function () { - this.stars.length = 0; - - for (let i = 0; i < 75; i++) { - this.stars.push({ - x: p5.random(0, 400), - y: p5.random(0, 250), - color: p5.lerpColor( - lerpColorFromPalette(p5.random()), - p5.color('#fff'), - 0.75 - ), - }); - } - }, - draw: function () { - p5.noFill(); - // Draw a horizontal gradient of the palette colors to the background - let ctx = p5._renderer.drawingContext; - ctx.save(); - let gradient = ctx.createLinearGradient(425, 425, 425, 0); - // Initialize first color stop so colors loop - let color = colorFromPalette(0); - gradient.addColorStop(0, color); - for (let i = 0; i < 5; i++) { - let color = colorFromPalette(i); - gradient.addColorStop((5 - i) / 5, color.toString()); - } - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 425, 425); - ctx.restore(); - - p5.noStroke(); - - for (const star of this.stars) { - const distanceFromCenter = 200 - star.x; - const opacity = p5.constrain(p5.cos(distanceFromCenter / 2), 0, 4); - const heightFade = p5.constrain(250 - star.y, 0, 500); - p5.push(); - p5.translate(star.x, star.y); - const sparkle = p5.constrain( - p5.noise(star.x / 50, star.y / 50, p5.frameCount / 50) + 0.4, - 0, - 1 - ); - p5.drawingContext.globalAlpha = opacity * (heightFade / 100) * 0.85; - p5.scale(1 / sparkle); - drawSparkle(p5._renderer.drawingContext, star.color); - p5.pop(); - - // Move the star to the left. - star.x -= 4.5 - opacity * 1.5; - - // If we've gone off-screen, loop around to the right. - if (star.x < 0) { - star.x = 400; - } - } - - p5.noiseDetail(50, 0.5); - p5.stroke('#999'); - p5.strokeWeight(2); - p5.line(200, 0, 200, 15); - p5.strokeWeight(0.25); - - const step = 20; - for (let i = 0; i <= 360; i += step) { - for (let j = 0; j < 180; j += step) { - p5.push(); - this.quad(i, j, step, p5.frameCount * 2); - p5.pop(); - } - } - }, - }; - - this.higher_power = { - init: function () {}, - draw: function () { - // The symbols are arranged to roughly fill a circle. These are [x,y] offset pairs. - const offsets = [ - [0, 270], - [61, 112], - [164, 1], - [312, 1], - [428, 66], - [591, 153], - [603, 323], - [491, 502], - [369, 502], - [237, 542], - [61, 438], - [200, 134], - [341, 173], - [473, 215], - [483, 340], - [353, 333], - [193, 419], - [141, 255], - [242, 248], - ]; - - let ctx = p5._renderer.drawingContext; - - ctx.save(); - let gradient = ctx.createLinearGradient(425, 425, 425, 0); - gradient.addColorStop( - 1, - constants.HIGHER_POWER_COLORS[getCurrentPalette()][0] - ); - gradient.addColorStop( - 0, - constants.HIGHER_POWER_COLORS[getCurrentPalette()][1] - ); - ctx.fillStyle = gradient; - ctx.fillRect(0, 0, 425, 425); - ctx.restore(); - - p5.push(); - p5.translate(p5.width / 2, p5.height / 2); - p5.imageMode(p5.CENTER); - p5.rotate(p5.frameCount); - p5.scale(1.7); - extraImages['higherPower'].drawFrame(19, 0, 0); - p5.pop(); - - // There is a low frequency oscillation between equal-size symbols and - // different-size symbols. - const scaleContribution = Math.sin(p5.frameCount / 200); - - offsets.forEach(function (offset, symbolIndex) { - p5.push(); - p5.translate(p5.width / 2, p5.height / 2); - p5.imageMode(p5.CENTER); - p5.rotate(-p5.frameCount * 3); - p5.translate(offset[0] * 0.4 - 120, offset[1] * 0.4 - 120); - p5.rotate(p5.frameCount * 5); - p5.scale( - 0.27 + - (scaleContribution * - Math.sin(p5.frameCount / 100 + symbolIndex * 40)) / - 3 - ); - extraImages['higherPower'].drawFrame(symbolIndex, 0, 0); - p5.pop(); - }); - }, - }; - - this.rainbow = { - lengths: [0, 0, 0, 0, 0, 0, 0], - current: 0, - update: function () { - this.lengths[this.lengths.length - (1 + this.current)] = 1; - this.current = (this.current + 1) % this.lengths.length; - }, - draw: function ({isPeak, bpm}) { - if (isPeak) { - this.update(); - } - p5.push(); - let backgroundColor = lerpColorFromPalette(0.5); - // Hack to set alpha for p5 - backgroundColor._array[3] = 0.25; - p5.background(backgroundColor); - p5.noFill(); - p5.strokeWeight(50); - let d, i; - for (i = 0; i < 7; i++) { - let paletteColor = lerpColorFromPalette(i * 0.14); - paletteColor._array[3] = 0.5; - p5.stroke(paletteColor); - d = 150 + i * 100; - p5.arc(0, 400, d, d, -90, 0); - if (this.lengths[i] > 0) { - // Hack to set RGB and Alpha values of p5 color objects - let [red, green, blue] = paletteColor.levels; - paletteColor.levels[0] = red - 20; - paletteColor.levels[1] = green - 20; - paletteColor.levels[2] = blue - 20; - paletteColor._array[3] = 1 - this.lengths[i] / 90; - p5.stroke(paletteColor); - p5.arc(0, 400, d, d, -90, -90 + this.lengths[i]); - this.lengths[i] = (this.lengths[i] + bpm / 50) % 90; - } - } - p5.pop(); - }, - }; - - this.flowers = { - hue: 0, - - drawFlower: function (num_petals, color) { - p5.fill(color); - for (let i = 0; i < num_petals; i++) { - p5.rotate(360 / num_petals); - p5.ellipse(0, 30, 20, 80); - } - }, - - draw: function ({isPeak}) { - if (isPeak) { - this.hue += 25; - } - p5.push(); - p5.noStroke(); - p5.translate(200, 200); - p5.angleMode(p5.DEGREES); - for (let i = 9; i > -1; i--) { - p5.push(); - p5.scale(i); - this.drawFlower( - 8, - lerpColorFromPalette(((this.hue + i * 10) % 360) / 360) - ); - p5.pop(); - } - p5.pop(); - }, - }; - - this.color_cycle = { - color: 0, - update: function () { - this.color += 0.03; - }, - draw: function ({isPeak}) { - if (isPeak) { - this.update(); - } - p5.background(lerpColorFromPalette(this.color)); - }, - }; - - this.disco = { - bg: undefined, - colors: [], - squaresPerSide: 4, - minColorChangesPerUpdate: 5, - maxColorChangesPerUpdate: 9, - init: function () { - if (this.colors.length) { - return; - } - // Alpha is ignored for this effect to avoid memory leaks with too many - // layers of alpha blending. - this.colors.length = this.squaresPerSide * this.squaresPerSide; - for (let i = 0; i < this.colors.length; i++) { - this.colors[i] = lerpColorFromPalette(p5.random(0, 1)); - } - }, - update: function () { - const numChanges = randomNumber( - this.minColorChangesPerUpdate, - this.maxColorChangesPerUpdate - ); - for (let i = 0; i < numChanges; i++) { - const loc = randomNumber(0, this.colors.length); - this.colors[loc] = lerpColorFromPalette(p5.random(0, 1)); - } - }, - draw: function ({isPeak}) { - if (isPeak) { - this.update(); - } - p5.push(); - p5.noStroke(); - const squareWidth = p5.width / this.squaresPerSide; - const squareHeight = p5.height / this.squaresPerSide; - for (let i = 0; i < this.colors.length; i++) { - p5.fill(this.colors[i]); - p5.rect( - (i % this.squaresPerSide) * squareWidth, - Math.floor(i / this.squaresPerSide) * squareHeight, - squareWidth, - squareHeight - ); - } - p5.pop(); - }, - }; - - // Creates a "ripple" effect where the ripple positions can be random. - let createRipplesEffect = function (isRandomRipple) { - return { - // Determines whether or not the start positions of the ripples are random or centered. - isRandomRipple: isRandomRipple, - // The max width a ripple can be before it disappears. - maxRippleWidth: 575, - // The ripples which are growing. - ripples: [], - // The count of ripples which have been created since the dance started. - rippleCount: 0, - // The timestamp of when the last "draw" happened. - lastDrawTime: new Date(), - // Tracks the last biggest ripple's color so we can set that as the background after it disappears - backgroundColor: colorFromPalette(0), - - init: function () { - this.lastDrawTime = new Date(); - this.backgroundColor = colorFromPalette(0); - this.ripples = []; - // If the starting location is random, then the circles might need to be 2x as wide to fill the screen. - if (isRandomRipple) { - this.maxRippleWidth = 1150; - } - // put some initial ripples. - for (let i = 0; i < 6; i++) { - this.ripples.push( - this.createRipple( - this.maxRippleWidth * (0.85 - 0.15 * i), - this.isRandomRipple - ) - ); - } - }, - - draw: function ({isPeak, bpm}) { - let currentTime = new Date(); - let maxRippleWidth = this.maxRippleWidth; - p5.background(this.backgroundColor); - // On each "peak", create a new ripple. - if (isPeak) { - this.ripples.push(this.createRipple(1, this.isRandomRipple)); - } - p5.push(); - p5.noStroke(); - p5.ellipseMode(p5.CENTER); - // calculate how much the ripples have grown and draw them. - let rippleWidthGrowth = this.getRippleGrowth(currentTime, bpm); - for (let i = 0; i < this.ripples.length; i++) { - let ripple = this.ripples[i]; - ripple.width += rippleWidthGrowth; - p5.fill(ripple.color); - p5.ellipse(ripple.x, ripple.y, ripple.width); - } - // remove ripples which are too big, and updated the backgroundColor to match the highest one. - let backgroundColor = this.backgroundColor; - this.ripples = this.ripples.filter(function (ripple) { - if (ripple.width < maxRippleWidth) { - return true; - } else { - backgroundColor = ripple.color; - return false; - } - }); - this.backgroundColor = backgroundColor; - p5.pop(); - // keep track of the draw times so we can calculate how much time has passed. - this.lastDrawTime = currentTime; - }, - - // creates a object representing the size and position of a ripple given an initial width - createRipple: function (width, isRandom) { - let x = 200; - let y = 200; - if (isRandom) { - x = randomNumber(20, 380); - y = randomNumber(20, 380); - } - return { - x: x, - y: y, - color: colorFromPalette(++this.rippleCount), - width: width, - }; - }, - - // calculates the increase in width a ripple will experience depending on the - // amount of time which has passed since the last drawm and the current BPM. - getRippleGrowth: function (currentTime, bpm) { - if (bpm === 0) { - return 0; - } - // Velocity of the ripple width expansion. - let velocity = this.maxRippleWidth / (bpm / 60) / 1.5; - // Calculate how much time has passed so we know how wide the ripple should be. - let deltaTime = (currentTime - this.lastDrawTime) / 1000; - return Math.floor(velocity * deltaTime); - }, - }; - }; - - this.ripples = createRipplesEffect(false); - this.ripples_random = createRipplesEffect(true); - - // This effect is slightly modified from Poetry background effect 'blooming' - // https://github.com/code-dot-org/code-dot-org/blob/381e9b93f7cbd081738dfa7adbc9e7ce4e169a0c/apps/src/p5lab/poetry/commands/backgroundEffects.js#L245 - this.blooming_petals = { - colorIndex: 0, - petals: [], - paletteLength: 0, - addPetalLayer: function (color, layer) { - for (let i = 0; i < 8; i++) { - this.petals.push({ - theta: 45 * i, - length: 10 + 140 * layer, - ...color, - }); - } - }, - init: function () { - this.paletteLength = constants.PALETTES[getCurrentPalette()].length; - this.petals = []; - // Initialize with enough petals to fill the screen - this is mostly - // useful so that preview shows what the background actually looks like. - // Increment from 3 down to 0 so that petals are layered correctly with - // bigger petals behind smaller petals. - for (let layer = 3; layer >= 0; layer--) { - const color = colorFromPalette(this.colorIndex); - this.addPetalLayer(hexToRgb(color), layer); - this.colorIndex = (this.colorIndex + 1) % this.paletteLength; - } - }, - draw: function () { - p5.push(); - p5.strokeWeight(2); - if (p5.World.frameCount % 70 === 0) { - const color = colorFromPalette(this.colorIndex); - this.addPetalLayer(hexToRgb(color), 0 /* layer */); - this.colorIndex = (this.colorIndex + 1) % this.paletteLength; - } - const petalWidth = 35; - this.petals.forEach(petal => { - // Multiply each component by 0.8 to have the stroke color be - // slightly darker than the fill color. - p5.stroke( - p5.color(petal.R * 0.8, petal.G * 0.8, petal.B * 0.8) - ); - p5.fill(p5.color(petal.R, petal.G, petal.B)); - drawPetal(p5, petal.length, petal.theta, petalWidth); - petal.theta = (petal.theta + 0.5) % 360; - petal.length += 2; - }); - this.petals = this.petals.filter(petal => petal.length < 700); - p5.pop(); - }, - }; - - // This effect is slightly modified from Poetry background effect 'clouds' - // https://github.com/code-dot-org/code-dot-org/blob/381e9b93f7cbd081738dfa7adbc9e7ce4e169a0c/apps/src/p5lab/poetry/commands/backgroundEffects.js#L368 - this.clouds = { - tileSize: 20, - tiles: [], - init: function () { - const noiseScale = 0.05; - this.tiles = []; - let xnoise = 0.01; - let ynoise = 0.01; - for (let x = 0; x < 400; x += this.tileSize) { - xnoise = 0.01; - for (let y = 0; y < 400; y += this.tileSize) { - this.tiles.push({ - x, - y, - xnoise, - ynoise, - }); - xnoise += noiseScale; - } - ynoise += noiseScale; - } - }, - draw: function () { - const speed = 0.015; - let backgroundAmount = 0; - p5.push(); - p5.noStroke(); - backgroundAmount += speed; - p5.background( - lerpColorFromPalette(backgroundAmount) - ); - this.tiles.forEach(tile => { - tile.alpha = p5.noise(tile.xnoise, tile.ynoise) * 255; - tile.xnoise += speed; - tile.ynoise += speed; - p5.fill(getP5Color(p5, '#ffffff', tile.alpha)); - p5.rect(tile.x, tile.y, this.tileSize, this.tileSize); - }); - p5.pop(); - }, - }; - - // This effect is slightly modified from Poetry background effect 'fadeColors' - // https://github.com/code-dot-org/code-dot-org/blob/381e9b93f7cbd081738dfa7adbc9e7ce4e169a0c/apps/src/p5lab/poetry/commands/backgroundEffects.js#L181 - this.frosted_grid = { - anchors: [], - circles: [], - spacing: 20, - init: function () { - this.anchors = []; - this.circles = []; - const paletteColors = constants.PALETTES[getCurrentPalette()]; - paletteColors.forEach(color => { - this.anchors.push({ - x: randomNumber(0, 400), - y: randomNumber(0, 400), - velocityX: randomNumber(-3, 3), - velocityY: randomNumber(-3, 3), - ...hexToRgb(color), - }); - }); - for (let x = 0; x < 420; x += this.spacing) { - for (let y = 0; y < 420; y += this.spacing) { - this.circles.push({x, y, red: 0, green: 0, blue: 0}); - } - } - }, - draw: function () { - p5.push(); - drawFrostedGrid(p5, this.anchors, this.circles, this.spacing); - p5.pop(); - }, - }; - - // This background effect is inspired by the Poetry foreground effect 'starburst' - // https://github.com/code-dot-org/code-dot-org/blob/381e9b93f7cbd081738dfa7adbc9e7ce4e169a0c/apps/src/p5lab/poetry/commands/foregroundEffects.js#L235 - this.starburst = { - stars: [], - init: function () { - this.stars = []; - p5.push(); - p5.background(lerpColorFromPalette(0)); - // A call to drawStarburst with isPreview=true will ensure background effect - // is displayed in preview. - drawStarburst(p5, true, this.stars, randomNumber, randomColorFromPalette, drawStar); - p5.pop(); - }, - draw: function () { - p5.push(); - p5.noStroke(); - p5.background(lerpColorFromPalette(0)); - drawStarburst(p5, false, this.stars, randomNumber, randomColorFromPalette, drawStar); - p5.pop(); - }, - }; - - this.diamonds = { - hue: 0, - update: function () { - this.hue += 25; - }, - draw: function ({isPeak, centroid}) { - if (isPeak) { - this.update(); - } - const centroidValue = this.getPreviewCustomizations().getCentroid(centroid); - p5.push(); - p5.rectMode(p5.CENTER); - p5.translate(200, 200); - p5.rotate(45); - p5.noFill(); - p5.strokeWeight(p5.map(centroidValue, 0, 4000, 0, 50)); - for (let i = 5; i > -1; i--) { - p5.stroke(lerpColorFromPalette(((this.hue + i * 10) % 360) / 360)); - p5.rect(0, 0, i * 100 + 50, i * 100 + 50); - } - p5.pop(); - }, - getPreviewCustomizations: function () { - return getInPreviewMode() ? - {getCentroid: () => 2000} : - {getCentroid: centroid => centroid}; - }, - }; - - this.circles = { - hue: 0, - update: function () { - this.hue += 25; - }, - draw: function ({isPeak}) { - if (isPeak) { - this.update(); - } - p5.push(); - p5.noStroke(); - p5.ellipseMode(p5.CENTER); - p5.translate(200, 200); - for (let i = 5; i > -1; i--) { - p5.fill(lerpColorFromPalette(((this.hue + i * 10) % 360) / 360)); - p5.ellipse(0, 0, i * 100 + 75, i * 100 + 75); - } - p5.pop(); - }, - }; - - this.rain = { - drops: [], - init: function () { - if (this.drops.length) { - return; - } - for (let i = 0; i < 20; i++) { - this.drops.push({ - x: randomNumber(0, 380), - y: randomNumber(0, 380), - length: randomNumber(10, 20), - }); - } - }, - color: p5.rgb(92, 101, 180, 0.5), - update: function () { - this.color = p5.rgb(92, 101, randomNumber(140, 220), 0.5); - }, - draw: function () { - p5.strokeWeight(3); - p5.stroke(this.color); - for (let i = 0; i < this.drops.length; i++) { - p5.push(); - p5.translate(this.drops[i].x - 20, this.drops[i].y - 20); - p5.line(0, 0, this.drops[i].length, this.drops[i].length * 2); - p5.pop(); - this.drops[i].y = (this.drops[i].y + this.drops[i].length) % 420; - this.drops[i].x = (this.drops[i].x + this.drops[i].length / 2) % 420; - } - }, - }; - - this.sparkles = { - sparkles: [], - maxSparkles: 80, - makeRandomSparkle: function () { - return { - x: randomNumber(-100, 600), - y: randomNumber(0, 400), - color: randomColorFromPalette(), - }; - }, - init: function () { - if (this.sparkles.length) { - return; - } - for (let i = 0; i < this.maxSparkles; i++) { - this.sparkles.push(this.makeRandomSparkle()); - } - }, - update: function () {}, - draw: function ({bpm}) { - // Provide a default value for bpm of song when not provided so that - // sparkles effect is drawn even in preview mode. - bpm = bpm || 120; - p5.background('#2b1e45'); - let velocity = Math.floor((bpm / 90) * 3); - for (let i = 0; i < this.maxSparkles; i++) { - p5.push(); - if (this.sparkles[i].x < 10 || this.sparkles[i].y > 410) { - this.sparkles[i] = this.makeRandomSparkle(); - } - - this.sparkles[i].x -= velocity; - this.sparkles[i].y += velocity; - p5.translate(this.sparkles[i].x, this.sparkles[i].y); - drawSparkle(p5._renderer.drawingContext, this.sparkles[i].color); - p5.pop(); - } - }, - }; - - this.text = { - texts: [], - maxTexts: 10, - update: function (text, hue, size) { - this.texts.push({ - x: randomNumber(25, 375), - y: randomNumber(25, 375), - text: text, - font: 'Arial', - color: lerpColorFromPalette(hue / 360), - size: size, - }); - if (this.texts.length > this.maxTexts) { - this.texts.shift(); - } - }, - draw: function ({isPeak, centroid, artist, title}) { - if (isPeak) { - let text; - if (randomNumber(0, 1) === 0) { - text = artist; - } else { - text = title; - } - this.update(text, centroid, randomNumber(14, 48)); - } - p5.push(); - p5.background(colorFromHue(0, 0, 40)); - p5.textAlign(p5.CENTER, p5.CENTER); - this.texts.forEach(function (t) { - p5.textSize(t.size); - p5.textFont(t.font); - p5.fill(t.color); - p5.text(t.text, t.x, t.y); - }); - p5.pop(); - }, - }; - - this.raining_tacos = { - tacos: [], - init: function () { - if (this.tacos.length) { - return; - } - for (let i = 0; i < 10; i++) { - this.tacos.push({ - x: randomNumber(20, 380), - y: this.getPreviewCustomizations().y, - rot: randomNumber(0, 359), - speed: 3, - size: 5, - }); - } - this.image = p5.createGraphics(125, 50); - this.image.scale(3); - drawTaco(this.image.drawingContext); - }, - draw: function (context) { - const centroid = this.getPreviewCustomizations().getCentroid(context); - for (let i = 0; i < this.tacos.length; i++) { - p5.push(); - const taco = this.tacos[i]; - let scale = p5.map(centroid, 5000, 8000, 0, taco.size); - scale = p5.constrain(scale, 0, 5); - p5.translate(taco.x, taco.y); - p5.rotate(taco.rot); - p5.scale(scale / (4 * p5.pixelDensity())); - p5.image(this.image); - taco.y += taco.speed; - taco.rot++; - if (taco.y > 420) { - taco.x = randomNumber(20, 380); - taco.y = -50; - } - p5.pop(); - } - }, - reset: function () { - this.tacos = []; - }, - getPreviewCustomizations: function () { - return getInPreviewMode() ? - { - y: randomNumber(0, 400), - getCentroid: () => 6500, - } : - { - y: randomNumber(-400, 0), - getCentroid: context => context.centroid, - }; - }, - }; - - this.pineapples = { - pineappleList: [], - init: function () { - if (this.pineappleList.length) { - return; - } - for (let i = 0; i < 8; i++) { - this.pineappleList.push({ - x: randomNumber(10, 390), - y: randomNumber(10, 390), - rot: randomNumber(0, 359), - life: 5, - }); - } - this.image = p5.createGraphics(75, 130); - this.image.scale(7); - drawPineapple(this.image.drawingContext); - }, - draw: function () { - for (let i = 0; i < this.pineappleList.length; i++) { - p5.push(); - const pineapple = this.pineappleList[i]; - const scale = this.getPreviewCustomizations().getScale(pineapple); - - p5.translate(pineapple.x, pineapple.y); - p5.rotate(pineapple.rot); - p5.scale(scale); - p5.drawingContext.drawImage(this.image.elt, -35, -65); - pineapple.life--; - if (pineapple.life < 0) { - pineapple.x = randomNumber(10, 390); - pineapple.y = randomNumber(10, 390); - pineapple.life = randomNumber(10, 120); - } - p5.pop(); - } - }, - reset: function () { - this.pineappleList = []; - }, - getPreviewCustomizations: function () { - return getInPreviewMode() ? - {getScale: () => randomNumber(10, 120) / 20 / (7 * p5.pixelDensity())} : - {getScale: pineapple => pineapple.life / 20 / (7 * p5.pixelDensity())}; - }, - }; - - this.splatter = { - buffer: null, - splats: [], - numSplats: 5, - randomSplat: function () { - return { - x: p5.random(0, 400), - y: p5.random(0, 400), - r: p5.random(5, 15), - color: randomColorFromPalette(), - }; - }, - init: function () { - this.splats.length = 0; - for (let i = 0; i < this.numSplats; i++) { - this.splats.push(this.randomSplat()); - } - - if (this.buffer) { - this.buffer.clear(); - return; - } - this.buffer = p5.createGraphics(p5.width, p5.height); - this.buffer.noStroke(); - this.buffer.drawingContext.globalAlpha = 0.8; - }, - draw: function () { - // first make a pass and remove items, traversing in reverse so that removals - // dont affect traversal - for (let splat of this.splats) { - if (splat.r > 30) { - splat.x = p5.random(0, 400); - splat.y = p5.random(0, 400); - splat.r = p5.random(5, 15); - splat.color = randomColorFromPalette(); - } - - splat.r += p5.random(1); - this.buffer.fill(splat.color); - for (let i = 0; i < 20; i++) { - this.buffer.ellipse( - p5.randomGaussian(splat.x, splat.r), - p5.randomGaussian(splat.y, splat.r), - p5.random(2, 8) - ); - } - } - - // Copy the off-screen buffer to the canvas. - p5.push(); - p5.scale(1 / p5.pixelDensity()); - p5.drawingContext.drawImage(this.buffer.elt, 0, 0); - p5.pop(); - }, - }; - - this.swirl = { - angle: 0, - color: null, - update: function () { - this.color = randomColorFromPalette(); - }, - draw: function ({isPeak, bpm}) { - if (isPeak || !this.color) { - this.update(); - } - p5.push(); - p5.background(this.color); - p5.translate(200, 200); - let rotation = (bpm / 90) * 50; - this.angle -= rotation; - p5.rotate((Math.PI / 180) * this.angle); - p5.translate(-427, -400); - drawSwirl(p5._renderer.drawingContext); - p5.pop(); - }, - }; - - this.spiral = { - angle: 0, - color: 0, - init: function () { - this.color = 0; - }, - update: function () { - this.color += 0.13; - if (this.color > 1) { - this.color -= 1; - } - }, - draw: function ({isPeak, bpm}) { - if (isPeak) { - this.update(); - } - p5.background(lerpColorFromPalette(this.color)); - p5.push(); - p5.translate(200, 200); - let rotation = (bpm / 90) * 200; - this.angle -= rotation; - p5.rotate((Math.PI / 180) * this.angle); - p5.translate(-600, -600); - drawSpiral(p5._renderer.drawingContext); - p5.pop(); - }, - }; - - this.spotlight = { - x: 200, - y: 200, - targetX: null, - targetY: null, - dx: 0, - dy: 0, - diameter: 0, - swirl: null, - init: function () { - this.targetX = 200; - this.targetY = 200; - this.update(); - }, - update: function () { - while ( - Math.sqrt( - (this.targetY - this.y) ** 2 + (this.targetX - this.x) ** 2 - ) < 40 - ) { - this.targetX = randomNumber(50, 350); - this.targetY = randomNumber(50, 350); - } - let angleOfMovement = Math.atan2( - this.targetY - this.y, - this.targetX - this.x - ); - this.dx = 6 * Math.cos(angleOfMovement); - this.dy = 6 * Math.sin(angleOfMovement); - }, - draw: function ({isPeak}) { - if ( - isPeak || - (Math.abs(this.targetX - this.x) < 4 && - Math.abs(this.targetY - this.y) < 4) - ) { - this.update(); - } - p5.push(); - p5.noFill(); - p5.stroke('#000'); - p5.strokeWeight(600); - this.x += this.dx + randomNumber(-1, 1); - this.y += this.dy + randomNumber(-1, 1); - p5.ellipse(this.x, this.y, 800, 800); - p5.pop(); - }, - }; - - this.lasers = { - laser: [], - init: function () { - this.laser.length = 0; - }, - draw: function () { - p5.background('black'); - if (this.laser.length < 32) { - const numLasersToDraw = this.getPreviewCustomizations().numLasersToDraw; - for (let i = 0; i < numLasersToDraw; i++) { - let laser = { - y: this.getPreviewCustomizations().getY(i), - color: this.getPreviewCustomizations().getColor(i) - }; - this.laser.push(laser); - } - } - p5.push(); - p5.translate(200, 180); - for (const [index, laser] of this.laser.entries()) { - let x = this.getPreviewCustomizations().getX(index); - if (x < 0) { - x *= -1; - } - const angle = p5.atan2(laser.y, x); - p5.stroke(laser.color); - p5.line(0, 0, p5.sin(angle) * 300, p5.cos(angle) * 300); - laser.y = laser.y - 100; - if (laser.y <= -1400) { - laser.y = 1750; - } - } - p5.pop(); - }, - reset: function () { - this.laser = []; - }, - // Note to future readers: at the time of writing, - // this implementation felt particularly hacky relative to other preview customizations. - // It's more challenging than many others, because the effect is "less random" than many other previews. - // Definitely open to alternative implementations as time allows! - getPreviewCustomizations: function () { - return getInPreviewMode() ? - { - numLasersToDraw: 32, - getY: iterationNum => 1750 - (iterationNum * 100), - getColor: iterationNum => lerpColorFromPalette(iterationNum / 16), - getX: iterationNum => 200 * p5.sin(iterationNum), - } : - { - numLasersToDraw: 1, - getY: () => 1750, - getColor: () => lerpColorFromPalette(p5.frameCount / 16), - getX: () => 200 * p5.sin(p5.frameCount), - }; - }, - }; - - this.quads = { - shapes: [], - init: function () { - if (!this.buffer) { - this.buffer = p5.createGraphics(400, 400); - this.buffer.noFill(); - this.buffer.stroke('#0f0'); - this.buffer.strokeWeight(2); - this.buffer.strokeJoin(p5.BEVEL); - this.buffer.background(0); - } - - for (let i = 0; i < 2; i++) { - const shape = []; - shape.color = i; - for (let j = 0; j < 4; j++) { - const vertex = p5.createSprite(); - vertex.draw = () => {}; - vertex.position = p5.createVector( - p5.random(0, 400), - p5.random(0, 400) - ); - vertex.velocity = p5.createVector(0, 2).rotate(p5.random(0, 360)); - shape.push(vertex); - } - this.shapes.push(shape); - } - this.edges = p5.createEdgeSprites(); - }, - reset: function () { - this.shapes = []; - p5.edges = null; - this.buffer.clear(); - }, - draw: function () { - this.buffer.drawingContext.globalAlpha = 0.25; - this.buffer.background(colorFromPalette(2)); - this.buffer.drawingContext.globalAlpha = 1; - - for (const shape of this.shapes) { - this.buffer.stroke(colorFromPalette(shape.color)); - this.buffer.quad.apply( - this.buffer, - shape.reduce((acc, current) => { - current.bounceOff(this.edges); - acc.push(current.position.x, current.position.y); - return acc; - }, []) - ); - } - - // Copy the off-screen buffer to the canvas. - p5.push(); - p5.scale(1 / p5.pixelDensity()); - p5.drawingContext.drawImage(this.buffer.elt, 0, 0); - p5.pop(); - }, - }; - - this.color_lights = { - lights: [], - newLight: function (x, arc, offset) { - return { - x: x, - arc: arc, - offset: offset, - shift: randomNumber(0, 359), - color: randomColor(100, 50, 0.25), - }; - }, - init: function () { - if (this.lights.length) { - return; - } - this.lights.push(this.newLight(75, 25, -10)); - this.lights.push(this.newLight(100, 15, -15)); - this.lights.push(this.newLight(300, 15, 15)); - this.lights.push(this.newLight(325, 25, 10)); - }, - update: function () { - this.lights.forEach(function (light) { - light.color = randomColor(100, 50, 0.25); - }); - }, - draw: function ({isPeak, centroid}) { - if (isPeak) { - this.update(); - } - p5.noStroke(); - this.lights.forEach(function (light) { - p5.push(); - p5.fill(light.color); - p5.translate(light.x, -50); - p5.rotate( - Math.sin(p5.frameCount / 100 + light.shift + centroid / 2000) * - light.arc + - light.offset - ); - p5.triangle(0, 0, -75, 600, 75, 600); - p5.pop(); - }); - }, - }; - - this.kaleidoscope = { - init: function () { - if (this.shapes) { - return; - } - - this.h = (Math.sqrt(3) / 2) * 100; - - this.shapes = p5.createGraphics(100, Math.ceil(this.h)); - this.shapes.noStroke(); - this.shapes.angleMode(p5.DEGREES); - - this.hex = p5.createGraphics(200, 200); - this.hex.angleMode(p5.DEGREES); - }, - blitHex: function () { - this.hex.push(); - this.hex.clear(); - this.hex.translate(100, 100); - this.hex.push(); - this.hex.scale(1 / p5.pixelDensity()); - this.hex.rotate(30); - for (let i = 0; i < 3; i++) { - this.hex.drawingContext.drawImage( - this.shapes.elt, - -50 * p5.pixelDensity(), - 0 - ); - this.hex.scale(-1, 1); - this.hex.rotate(60); - this.hex.drawingContext.drawImage( - this.shapes.elt, - -50 * p5.pixelDensity(), - 0 - ); - this.hex.rotate(60); - this.hex.scale(-1, 1); - } - this.hex.pop(); - this.hex.pop(); - }, - row: function (n) { - p5.push(); - for (let i = 0; i < n; i++) { - p5.push(); - p5.scale(1 / p5.pixelDensity()); - p5.drawingContext.drawImage( - this.hex.elt, - -100 * p5.pixelDensity(), - -100 * p5.pixelDensity() - ); - p5.pop(); - p5.translate(this.h * 2, 0); - } - p5.pop(); - }, - draw: function () { - p5.background(colorFromPalette(2)); - - const ctx = this.shapes.drawingContext; - ctx.save(); - ctx.beginPath(); - ctx.moveTo(50, 0); - ctx.lineTo(100, this.h); - ctx.lineTo(0, this.h); - ctx.clip(); - this.shapes.clear(); - this.shapes.rotate(p5.frameCount); - this.shapes.fill(colorFromPalette(0)); - this.shapes.rect(20, 20, 50, 50); - this.shapes.fill(colorFromPalette(2)); - this.shapes.triangle(0, 10, 80, 90, 0, 100); - this.shapes.fill(colorFromPalette(1)); - this.shapes.triangle(20, 0, 50, 30, 30, 60); - this.shapes.fill(colorFromPalette(4)); - this.shapes.ellipse(100, 50, 80); - this.shapes.fill(colorFromPalette(1)); - this.shapes.ellipse(-50, -50, 50); - this.shapes.fill(colorFromPalette(5)); - this.shapes.ellipse(-40, -46, 20); - this.shapes.fill(colorFromPalette(0)); - this.shapes.triangle(-60, 0, -30, -40, -30, 0); - this.shapes.fill(colorFromPalette(3)); - this.shapes.rect(-45, 0, 40, 300); - this.shapes.rotate(17); - this.shapes.fill(colorFromPalette(4)); - this.shapes.rect(30, 40, 10, 40); - this.shapes.rotate(37); - this.shapes.fill(colorFromPalette(6)); - this.shapes.rect(30, 40, 20, 40); - this.shapes.rotate(180); - this.shapes.fill(colorFromPalette(0)); - this.shapes.triangle(10, 20, 80, 90, 0, 100); - this.shapes.translate(20, 0); - this.shapes.rotate(20); - this.shapes.fill(colorFromPalette(3)); - this.shapes.rect(0, 0, 20, 200); - ctx.restore(); - - p5.push(); - this.blitHex(); - p5.imageMode(p5.CENTER); - - p5.translate(200, 200); - p5.rotate(p5.frameCount); - p5.scale(0.8); - - p5.translate(this.h * -2, -300); - this.row(3); - p5.translate(-this.h, 150); - this.row(4); - p5.translate(-this.h, 150); - this.row(5); - p5.translate(this.h, 150); - this.row(4); - p5.translate(this.h, 150); - this.row(3); - - p5.pop(); - }, - }; - - this.smiling_poop = { - poopList: [], - init: function () { - if (this.poopList.length) { - return; - } - for (let i = 0; i < 6; i++) { - this.poopList.push({ - x: randomNumber(10, 390), - y: randomNumber(10, 390), - rot: randomNumber(0, 359), - life: 5, - }); - } - }, - draw: function () { - for (const poop of this.poopList) { - const scale = this.getPreviewCustomizations().getScale(poop); - - p5.push(); - p5.translate(poop.x, poop.y); - p5.rotate(poop.rot); - p5.scale(scale); - drawPoop(p5._renderer.drawingContext); - poop.life--; - if (poop.life < 0) { - poop.x = randomNumber(10, 390); - poop.y = randomNumber(10, 390); - poop.life = randomNumber(10, 120); - } - p5.pop(); - } - }, - reset: function () { - this.poopList = []; - }, - getPreviewCustomizations: function () { - return getInPreviewMode() ? - {getScale: () => randomNumber(10, 120) / 20} : - {getScale: poop => poop.life / 20}; - }, - }; - - this.hearts_red = { - heartList: [], - init: function () { - if (this.heartList.length) { - return; - } - for (let i = 0; i < 10; i++) { - this.heartList.push({ - x: randomNumber(10, 390), - y: randomNumber(10, 390), - rot: randomNumber(0, 359), - life: randomNumber(10, 120), - color: p5.rgb(255, 0, 0, 0.5), - }); - } - }, - draw: function () { - for (const heart of this.heartList) { - p5.push(); - p5.translate(heart.x, heart.y); - p5.rotate(heart.rot); - p5.scale(heart.life / 20); - drawHeart(p5._renderer.drawingContext, heart.color); - heart.life--; - if (heart.life < 0) { - heart.x = randomNumber(10, 390); - heart.y = randomNumber(10, 390); - heart.life = randomNumber(10, 120); - } - p5.pop(); - } - }, - reset: function () { - this.heartList = []; - } - }; - - this.hearts_colorful = { - heartList: [], - init: function () { - if (this.heartList.length) { - return; - } - for (let i = 0; i < 10; i++) { - this.heartList.push({ - x: randomNumber(10, 390), - y: randomNumber(10, 390), - rot: randomNumber(0, 359), - life: randomNumber(10, 120), - color: randomColor(100, 50, 0.25), - }); - } - }, - draw: function () { - for (let i = 0; i < this.heartList.length; i++) { - p5.push(); - const heart = this.heartList[i]; - p5.translate(heart.x, heart.y); - p5.rotate(heart.rot); - p5.scale(heart.life / 20); - drawHeart(p5._renderer.drawingContext, heart.color); - heart.life--; - if (heart.life < 0) { - heart.x = randomNumber(10, 390); - heart.y = randomNumber(10, 390); - heart.life = randomNumber(10, 120); - } - p5.pop(); - } - }, - reset: function () { - this.heartList = []; - } - }; - - this.floating_rainbows = { - rainbows: [], - init: function () { - if (this.rainbows.length) { - return; - } - - for (let i = 0; i < 15; i++) { - this.rainbows.push({ - x: randomNumber(10, 390), - y: this.getPreviewCustomizations().y, - rot: randomNumber(0, 359), - speed: 2, - size: randomNumber(1.5, 3), - }); - } - this.image = p5.createGraphics(175, 100); - this.image.scale(3); - drawRainbow(this.image.drawingContext); - }, - draw: function (context) { - const centroid = this.getPreviewCustomizations().getCentroid(context); - - for (let i = 0; i < this.rainbows.length; i++) { - p5.push(); - const rainbows = this.rainbows[i]; - let scale = p5.map(centroid, 5000, 8000, 0, rainbows.size); - scale = p5.constrain(scale, 0, 3); - p5.translate(rainbows.x, rainbows.y); - p5.scale(scale / (2 * p5.pixelDensity())); - p5.image(this.image); - rainbows.y -= rainbows.speed; - if (rainbows.y < -25) { - rainbows.x = randomNumber(10, 390); - rainbows.y = 450; - } - p5.pop(); - } - }, - reset: function () { - this.rainbows = []; - }, - getPreviewCustomizations: function () { - return getInPreviewMode() ? - { - y: randomNumber(0, 400), - getCentroid: () => 6500, - } : - { - y: randomNumber(400, 800), - getCentroid: context => context.centroid, - }; - }, - }; - - this.snowflakes = { - flake: [], - draw: function () { - p5.background(lerpColorFromPalette(0.5)); - const numSnowflakesToDraw = this.getPreviewCustomizations().numSnowflakesToDraw; - for (let i = 0; i < numSnowflakesToDraw; i++) { - let flake = { - x: p5.random(-100, 400), - y: this.getPreviewCustomizations().y, - velocityX: p5.random(-2, 2), - size: p5.random(6, 12), - }; - this.flake.push(flake); - } - p5.noStroke(); - p5.fill('white'); - this.flake.forEach(function (flake) { - p5.push(); - p5.translate(flake.x, flake.y); - for (let i = 0; i < 5; i++) { - p5.rotate(360 / 5); - p5.ellipse(0, 0, 1, flake.size); - } - let fallSpeed = p5.map(flake.size, 6, 12, 2, 5); - flake.y += fallSpeed; - flake.x += flake.velocityX; - p5.pop(); - }); - this.flake = this.flake.filter(function (flake) { - return flake.y < 425; - }); - }, - reset: function () { - this.flake = []; - }, - getPreviewCustomizations: function () { - return getInPreviewMode() ? - {numSnowflakesToDraw: 200, y: p5.random(-100, 400)} : - {numSnowflakesToDraw: 1, y: -10}; - }, - }; - - this.fireworks = { - particles: [], - minExplosion: 20, - maxExplosion: 50, - minPotential: 200, - maxPotential: 300, - buffer: null, - - makeParticle: function (type, pos, vel, color, potential) { - return { - type: type, - pos: pos, - vel: vel, - gravity: p5.createVector(0.0, 0.1), - potential: potential, - acc: p5.createVector(0, 0), - color: color, - alpha: 1, - update: function () { - this.acc.add(this.gravity); - this.vel.add(this.acc); - this.pos.add(this.vel); - this.acc.mult(0, 0); - }, - }; - }, - - init: function () { - if (this.buffer) { - return; - } - // We get the tracer effect by writing frames to a - // off-screen buffer that has a transparent background. - this.buffer = p5.createGraphics(p5.width, p5.height); - }, - - draw: function () { - p5.background(0); - this.buffer.background(0, 25); - - p5.push(); - this.drawParticles(); - - // Copy the off-screen buffer to the canvas. - p5.scale(1 / p5.pixelDensity()); - p5.drawingContext.drawImage(this.buffer.elt, 0, 0); - - p5.pop(); - - this.particles = this.nextParticles(); - }, - - drawParticles: function () { - for (var i = 0; i < this.particles.length; i++) { - let p = this.particles[i]; - p.update(); - - this.buffer.push(); - if (p.type === 'rocket') { - this.buffer.strokeWeight(3); - this.buffer.stroke(p.color); - this.buffer.point(p.pos.x, p.pos.y); - } else if (p.type === 'particle') { - this.buffer.translate(p.pos.x, p.pos.y); - this.buffer.drawingContext.globalAlpha = p.alpha; - p.alpha = p5.constrain(p.alpha - 0.02, 0, 1); - drawSparkle(this.buffer.drawingContext, p.color); - } - this.buffer.pop(); - } - }, - - nextParticles: function () { - let ret = []; - - // total potential is the number of particles active, or the number represented - // in unexploded rockets. This is how we manage total number of objects - var totalPotential = 0; - for (var i = 0; i < this.particles.length; i++) { - let p = this.particles[i]; - - if (p.type === 'rocket') { - // explode a rocket when it reaches it peak height - if (p.vel.y <= 0) { - ret.push(p); - } else { - ret = ret.concat(this.explode(p)); - } - - // the rocket exploded to its potential or its still waiting - totalPotential += p.potential; - } else if (p.type === 'particle') { - // remove things when they leave the window, except allow particles - // to fall back down into the view from above - if (p.pos.x > 0 && p.pos.x < p5.width && p.pos.y < p5.height) { - ret.push(p); - totalPotential += p.potential; - } - } - } - - // make sure the total potential for particles is between the min and max potential - if (totalPotential < this.minPotential) { - // fire rockets until we fill the potential - while (totalPotential < this.maxPotential) { - let p = this.makeParticle( - 'rocket', - p5.createVector(randomNumber(0, p5.height), p5.width), - p5.createVector(0, p5.random(-9, -7)), - randomColorFromPalette(), - p5.random(this.minExplosion, this.maxExplosion) - ); - totalPotential += p.potential; - ret.push(p); - } - } - return ret; - }, - - explode: function (p) { - let ret = []; - for (var i = 0; i < p.potential; i++) { - ret.push( - this.makeParticle( - 'particle', - p5.createVector(p.pos.x, p.pos.y), - p5.createVector(p5.random(-5, 5), p5.random(-5, 5)), - p.color, - 1 - ) - ); - } - return ret; - }, - }; - - this.bubbles = { - bubble: [], - draw: function () { - const numBubblesToDraw = this.getPreviewCustomizations().numBubblesToDraw; - for (let i = 0; i < numBubblesToDraw; i++) { - let bubble = { - x: p5.random(-100, 400), - y: this.getPreviewCustomizations().y, - velocityX: p5.random(-2, 2), - size: p5.random(6, 12, 18), - color: randomColor(100, 50, 0.25), - }; - this.bubble.push(bubble); - } - - p5.noStroke(); - this.bubble.forEach(function (bubble) { - p5.push(); - p5.fill(bubble.color); - p5.translate(bubble.x, bubble.y); - p5.ellipse(0, 0, bubble.size, bubble.size); - let fallSpeed = p5.map(bubble.size, 6, 12, 1, 3); - bubble.y -= fallSpeed; - bubble.x += bubble.velocityX; - p5.pop(); - }); - this.bubble = this.bubble.filter(function (bubble) { - return bubble.y > 0; - }); - }, - reset: function () { - this.bubble = []; - }, - getPreviewCustomizations: function () { - return getInPreviewMode() ? - {numBubblesToDraw: 200, y: p5.random(-100, 400)} : - {numBubblesToDraw: 1, y: 410}; - } - }; - - this.stars = { - star: [], - draw: function () { - p5.background('#303030'); - const numStarsToDraw = this.getPreviewCustomizations().numStarsToDraw; - for (let i = 0; i < numStarsToDraw; i++) { - let star = { - x: p5.random(0, 400), - y: p5.random(0, 400), - size: p5.random(15, 30), - color: randomColorFromPalette(), - }; - this.star.push(star); - } - - p5.noStroke(); - this.star.forEach(function (star) { - p5.push(); - p5.fill(star.color); - p5.translate(star.x, star.y); - for (let i = 0; i < 3; i++) { - p5.rotate(360 / 5); - p5.ellipse(0, 0, 1, star.size); - } - let fadeSpeed = p5.map(star.size, 15, 30, 1, 2); - star.size = star.size - fadeSpeed; - star.y = star.y - 2; - p5.pop(); - }); - this.star = this.star.filter(function (star) { - return star.size > 0.1; - }); - }, - reset: function () { - this.star = []; - }, - getPreviewCustomizations: function () { - return getInPreviewMode() ? - {numStarsToDraw: 30} : - {numStarsToDraw: 1}; - } - }; - - this.exploding_stars = { - stars: [], - init: function () { - this.stars = []; - for (let i = 0; i < 100; i++) { - let theta = p5.random(0, 360); - let velocity = p5.random(4, 12); - - this.stars.push({ - color: randomColor(255, 255, 100), - x: this.getPreviewCustomizations().x, - y: this.getPreviewCustomizations().y, - dx: velocity * p5.cos(theta), - dy: velocity * p5.sin(theta), - }); - } - }, - draw: function () { - p5.angleMode(p5.DEGREES); - p5.noStroke(); - if (this.stars.length === 0) { - this.init(); - } - this.stars.forEach(star => { - p5.fill(star.color); - drawStar(p5, star.x, star.y, 3, 9, 5); - star.x += star.dx; - star.y += star.dy; - }); - this.stars = this.stars.filter( - star => star.x > -10 && star.x < 410 && star.y > -10 && star.y < 410 - ); - }, - getPreviewCustomizations: function () { - return getInPreviewMode() ? - {x: randomNumber(0, 400), y: randomNumber(0, 400)} : - {x: 200, y: 200}; - } - }; - - this.galaxy = { - asteroid: [], - draw: function () { - p5.background('black'); - const numAsteroidsToDraw = this.getPreviewCustomizations().numAsteroidsToDraw; - for (let i = 0; i < numAsteroidsToDraw; i++) { - let asteroid = { - x: this.getPreviewCustomizations().x, - y: this.getPreviewCustomizations().y, - velocity: p5.createVector(0, 1).rotate(p5.random(0, 360)), - size: this.getPreviewCustomizations().size, - color: randomColorFromPalette(), - }; - this.asteroid.push(asteroid); - } - p5.noStroke(); - - this.asteroid.forEach(asteroid => { - p5.push(); - p5.fill(asteroid.color); - p5.translate(asteroid.x, asteroid.y); - p5.ellipse(0, 0, asteroid.size, asteroid.size); - let speedMultiplier = p5.pow(asteroid.size, 2) / 2; - asteroid.x += this.getPreviewCustomizations().getMovementDistance(asteroid.velocity.x, speedMultiplier); - asteroid.y += this.getPreviewCustomizations().getMovementDistance(asteroid.velocity.y, speedMultiplier); - asteroid.size += 0.1; - p5.pop(); - }); - this.asteroid = this.asteroid.filter(function (asteroid) { - if (asteroid.x < -5 || asteroid.x > 405 || asteroid.y < -5 || asteroid.y > 405) { - return false; - } - return true; - }); - }, - reset: function () { - this.asteroid = []; - }, - getPreviewCustomizations: function () { - return getInPreviewMode() ? - { - numAsteroidsToDraw: 200, - size: 3, - x: randomNumber(0, 400), - y: randomNumber(0, 400), - getMovementDistance: () => 0, - } : - { - numAsteroidsToDraw: 3, - size: 0.01, - x: 200, - y: 200, - getMovementDistance: (dimension, multiplier) => dimension * multiplier - }; - } - }; - - this.pizzas = { - pizza: [], - init: function () { - if (this.pizza.length) { - return; - } - for (let i = 0; i < 10; i++) { - this.pizza.push({ - x: randomNumber(25, 375), - y: randomNumber(25, 375), - size: randomNumber(2, 6), - rot: randomNumber(0, 359), - life: 200, - }); - } - this.image = p5.createGraphics(100, 100); - this.image.scale(3); - drawPizza(this.image.drawingContext); - }, - draw: function (context) { - const centroid = this.getPreviewCustomizations().getCentroid(context); - for (let i = 0; i < this.pizza.length; i++) { - p5.push(); - const pizza = this.pizza[i]; - let scale = p5.map(centroid, 5000, 8000, 0, pizza.size); - scale = p5.constrain(scale, 0, 5); - p5.translate(pizza.x, pizza.y); - p5.rotate(pizza.rot); - p5.scale(scale / (4 * p5.pixelDensity())); - p5.drawingContext.drawImage(this.image.elt, 0, 0); - pizza.life--; - if (pizza.life < 0) { - (pizza.x = randomNumber(25, 375)), - pizza.y - randomNumber(25, 375), - (pizza.life = 200); - } - p5.pop(); - } - }, - getPreviewCustomizations: function () { - return getInPreviewMode() ? - {getCentroid: () => 6500} : - {getCentroid: context => context.centroid}; - }, - }; - - this.smile_face = { - smiles: [], - init: function () { - if (this.smiles.length) { - return; - } - for (let i = 0; i < 10; i++) { - this.smiles.push({ - x: randomNumber(25, 375), - y: randomNumber(25, 375), - size: randomNumber(2, 6), - rot: randomNumber(0, 359), - life: 200, - }); - } - this.image = p5.createGraphics(100, 100); - this.image.scale(3); - drawSmiley(this.image.drawingContext, 0.8); - }, - draw: function (context) { - const centroid = this.getPreviewCustomizations().getCentroid(context); - - for (let i = 0; i < this.smiles.length; i++) { - p5.push(); - const smiles = this.smiles[i]; - let scale = p5.map(centroid, 5000, 8000, 0, smiles.size); - scale = p5.constrain(scale, 0, 5); - p5.translate(smiles.x, smiles.y); - p5.rotate(smiles.rot); - p5.scale(scale / (4 * p5.pixelDensity())); - p5.drawingContext.drawImage(this.image.elt, 0, 0); - smiles.life--; - if (smiles.life < 0) { - (smiles.x = randomNumber(25, 375)), - smiles.y - randomNumber(25, 375), - (smiles.life = 200); - } - p5.pop(); - } - }, - getPreviewCustomizations: function () { - return getInPreviewMode() ? - {getCentroid: () => 6500} : - {getCentroid: context => context.centroid}; - }, - }; - - this.confetti = { - confetti: [], - draw: function () { - const numConfettiToDraw = this.getPreviewCustomizations().numConfettiToDraw; - for (let i = 0; i < numConfettiToDraw; i++) { - const spin = this.getPreviewCustomizations().spin; - let confetti = { - x: p5.random(-100, 400), - y: this.getPreviewCustomizations().y, - velocityX: p5.random(-2, 2), - size: p5.random(6, 12, 18), - // https://github.com/Automattic/node-canvas/issues/702 - // Bug with node-canvas prevents scaling with a value of 0, so spin initializes to 1 - spin: spin, - color: randomColor(255, 255, 100), - }; - - this.confetti.push(confetti); - } - - p5.noStroke(); - this.confetti.forEach(function (confetti) { - p5.push(); - p5.fill(confetti.color); - p5.translate(confetti.x, confetti.y); - const scaleX = p5.sin(confetti.spin); - p5.scale(scaleX, 1); - confetti.spin += 20; - p5.rect(0, 0, 4, confetti.size); - let fallSpeed = p5.map(confetti.size, 6, 12, 1, 3); - confetti.y += fallSpeed; - confetti.x += confetti.velocityX; - p5.pop(); - }); - this.confetti = this.confetti.filter(function (confetti) { - return confetti.y < 425; - }); - }, - reset: function () { - this.confetti = []; - }, - getPreviewCustomizations: function () { - return getInPreviewMode() ? - {numConfettiToDraw: 200, spin: p5.random(1, 80), y: p5.random(-100, 400)} : - {numConfettiToDraw: 1, spin: 1, y: -10}; - } - }; - - this.growing_stars = { - stars: [], - colorIndex: 0, - starSpacing: 30, - numStars: 9, - - init: function () { - p5.angleMode(p5.DEGREES); - this.colorIndex = 0; - this.stars = []; - for (var i = 0; i < this.numStars; i++) { - this.stars.push({ - size: this.starSpacing * (this.numStars - i), - colorIndex: this.colorIndex, - }); - this.colorIndex++; - } - }, - - draw: function () { - for (let star of this.stars) { - p5.fill(colorFromPalette(star.colorIndex)); - drawStar(p5, 200, 200, star.size, star.size * 2.5, 5); - star.size += 1; - } - if (this.stars[0].size > this.starSpacing * this.numStars) { - this.stars.shift(); - this.stars.push({size: 0, colorIndex: this.colorIndex}); - this.colorIndex++; - } - }, - }; - - this.music_notes = { - notes: [], - init: function () { - if (this.notes.length) { - return; - } - for (let i = 0; i < 20; i++) { - this.notes.push({ - x: randomNumber(10, 390), - y: this.getPreviewCustomizations().y, - rot: randomNumber(0, 359), - speed: 2, - size: randomNumber(1.5, 3), - }); - } - this.image = p5.createGraphics(70, 50); - this.image.scale(4); - drawMusicNote(this.image.drawingContext); - }, - draw: function (context) { - const centroid = this.getPreviewCustomizations().getCentroid(context); - for (let i = 0; i < this.notes.length; i++) { - p5.push(); - const notes = this.notes[i]; - let scale = p5.map(centroid, 5000, 8000, 0, notes.size); - scale = p5.constrain(scale, 0, 3); - p5.translate(notes.x, notes.y); - p5.rotate(notes.rot); - p5.scale(scale / (4 * p5.pixelDensity())); - p5.drawingContext.drawImage(this.image.elt, 0, 0); - notes.y += notes.speed; - notes.rot++; - if (notes.y > 410) { - notes.x = randomNumber(10, 390); - notes.y = -50; - } - p5.pop(); - } - }, - reset: function () { - this.notes = []; - }, - getPreviewCustomizations: function () { - return getInPreviewMode() ? - {y: randomNumber(0, 390), getCentroid: () => 6500} : - {y: randomNumber (-400, 0), getCentroid: context => context.centroid}; - }, - }; - - this.paint_drip = { - current_drip: 0, - current_drip_height: 0, - crayons: [], - start_width: 15, - start_height: 30, - dripping_up: false, - drip_diameter: 20, - drip_speed: 7, - - reset: function () { - this.init(); - this.dripping_up = false; - }, - init: function () { - // Reset values - this.current_drip = 0; - this.current_drip_height = 0; - this.crayons = []; - - this.crayons.push({maxHeight: p5.random(30, 200), startFrame: 0}); - for (let i = 0; i < 17; i++) { - this.crayons.push({maxHeight: 0, startFrame: 0}); - } - }, - draw: function () { - for (let i = 0; i < this.crayons.length; i++) { - let c = lerpColorFromSpecificPalette('neon', i / this.crayons.length); - p5.fill(c); - p5.noStroke(); - let rectHeight = this.getPreviewCustomizations().getRectHeight(); - - // Drip is to the left of moving drip and should be stationary at full height - if (i < this.current_drip) { - rectHeight = this.crayons[i].maxHeight; - // Drip is currently moving - } else if (i === this.current_drip) { - //Calculate height with regard to direction of movement - if (this.dripping_up) { - rectHeight = - this.crayons[i].maxHeight - - (p5.frameCount - this.crayons[i].startFrame) * this.drip_speed; - } else { - rectHeight = - (p5.frameCount - this.crayons[i].startFrame) * this.drip_speed + - this.start_height; - } - this.current_drip_height = rectHeight; - } - //Draw each drip with a rectangle and ellipse - p5.rect(22 * i + 7, 0, this.start_width, rectHeight); - p5.ellipse( - 22 * i + this.start_width, - rectHeight, - this.drip_diameter, - this.drip_diameter - ); - } - - // Check if the current drip is 'done' - if ( - (!this.dripping_up && - this.current_drip_height >= - this.crayons[this.current_drip].maxHeight) || - (this.dripping_up && this.current_drip_height <= 30) - ) { - if ( - !this.dripping_up && - this.current_drip === this.crayons.length - 1 - ) { - // The rightmost drip is 'done' dripping down, switch to dripping up. - this.dripping_up = true; - this.current_drip_height = - this.crayons[this.current_drip].maxHeight; - } else if (this.dripping_up && this.current_drip === 0) { - // The leftmost drip is 'done' dripping up, switch to dripping down. - this.dripping_up = false; - this.current_drip_height = 0; - } else if (this.dripping_up) { - // A non-edge drip is 'done' dripping up, move the next left drip. - this.current_drip -= 1; - this.current_drip_height = - this.crayons[this.current_drip].maxHeight; - } else { - // A non-edge drip is 'done' dripping down, move the next drip right. - this.current_drip += 1; - this.current_drip_height = 0; - //Each new drip down is assigned a random maximum height. - this.crayons[this.current_drip].maxHeight = p5.random(30, 200); - } - //Note when this drip started to calculate the height in mid-drip - this.crayons[this.current_drip].startFrame = p5.frameCount; - } - }, - getPreviewCustomizations: function () { - return getInPreviewMode() ? - {getRectHeight: () => p5.random(30, 200)} : - {getRectHeight: () => this.start_height}; - } - }; - - this.squiggles = { - points: [], - dotSpacing: 4, - amplitude: 40, - period: 400, - dotRadius: 14, - numSquiggles: 5, - init: function () { - this.points = []; - p5.noStroke(); - p5.angleMode(p5.DEGREES); - let numPoints = p5.height / this.dotSpacing; - for (var i = 0; i < numPoints; i++) { - this.points.push({ - x: 0, - y: i * this.dotSpacing, - theta: (360 / this.period) * i * this.dotSpacing, - color: lerpColorFromPalette(i / numPoints), - }); - } - }, - draw: function ({bpm}) { - p5.background('black'); - for (var i = 0; i < this.numSquiggles; i++) { - this.points.forEach(point => { - p5.fill(point.color); - p5.ellipse(point.x, point.y, this.dotRadius, this.dotRadius); - point.x = - (p5.width / (this.numSquiggles - 1)) * i + - p5.sin(point.theta) * this.amplitude; - point.theta = (point.theta + bpm / 360) % 360; - }); - } - }, - }; - - this.music_wave = { - inc: 360 / 15, - heightFactor: 1, - heightDivider: 200, - yLoc: 300, - lineWidth: p5.width / 80, - draw: function (context) { - const centroid = context.centroid; - let scale = p5.map(centroid, 5000, 8000, 0, 250); - let angle = 0; - p5.background('black'); - for (let i = 0; i < p5.width; i += this.lineWidth) { - p5.stroke(lerpColorFromPalette(i / p5.width)); - let amplitude = Math.abs( - scale * (this.heightFactor / this.heightDivider) * p5.cos(angle) - ); - let yInitial = this.yLoc - amplitude; - let yFinal = this.yLoc + amplitude; - p5.line(i, yInitial, i, yFinal); - if (i < p5.width / 2) { - this.heightFactor++; - } else { - this.heightFactor--; - } - angle += this.inc; - } - }, - }; - - this.emojis = { - emojiList: [], - emojiTypes: [], - - init: function () { - this.imageLovestruck = p5.createGraphics(100, 100); - this.imageLovestruck.scale(3); - drawLovestruck(this.imageLovestruck.drawingContext); - this.emojiTypes.push(this.imageLovestruck); - - this.imageSmiley = p5.createGraphics(100, 100); - this.imageSmiley.scale(3); - drawSmiley(this.imageSmiley.drawingContext, 1.0); - this.emojiTypes.push(this.imageSmiley); - - this.imageStarstruck = p5.createGraphics(100, 100); - this.imageStarstruck.scale(3); - drawStarstruck(this.imageStarstruck.drawingContext); - this.emojiTypes.push(this.imageStarstruck); - - this.imageTickled = p5.createGraphics(100, 100); - this.imageTickled.scale(3); - drawTickled(this.imageTickled.drawingContext); - this.emojiTypes.push(this.imageTickled); - - this.imageWink = p5.createGraphics(100, 100); - this.imageWink.scale(3); - drawWink(this.imageWink.drawingContext); - this.emojiTypes.push(this.imageWink); - }, - - draw: function () { - this.getPreviewCustomizations().addEmojis(); - - for (let i = 0; i < this.emojiList.length; ++i) { - const emoji = this.emojiList[i]; - emoji.y += p5.pow(emoji.size, 0.25); // emoji falls at a rate fourth root to its size - if (emoji.y > p5.height * 1.2) { - // if the emoji has fallen past 120% of the screen - this.emojiList.splice(i, 1); - } - p5.push(); - p5.drawingContext.drawImage( - emoji.image.elt, - emoji.x, - emoji.y, - emoji.size, - emoji.size - ); - p5.pop(); - } - }, - reset: function () { - this.emojiList = []; - }, - getPreviewCustomizations: function () { - if (getInPreviewMode()) { - const addEmojisPreview = () => { - if (this.emojiList.length) { - return; - } - - for (let i = 0; i < 12; i++) { - this.emojiList.push({ - x: randomNumber(0, 350), - y: randomNumber(0, 350), - size: randomNumber(50, 90), - image: this.emojiTypes[randomNumber(0, 4)], - }); - } - }; - return {addEmojis: addEmojisPreview}; - } else { - const addEmojisDefault = () => { - if (p5.frameCount % 10 === 0) { - // generate new emoji every 10 frames - this.emojiList.push({ - x: randomNumber(0, 350), - y: -50, - size: randomNumber(50, 90), - image: this.emojiTypes[randomNumber(0, 4)], - }); - } - }; - return {addEmojis: addEmojisDefault}; - } - }, - }; + // background + this.disco_ball = discoBall(p5, lerpColorFromPalette, colorFromPalette); + this.higher_power = higherPower(p5, getCurrentPalette, extraImages); + this.rainbow = rainbow(p5, lerpColorFromPalette); + this.flowers = flowers(p5, lerpColorFromPalette); + this.color_cycle = colorCycle(p5, lerpColorFromPalette); + this.disco = disco(p5, lerpColorFromPalette, randomNumber); + this.ripples = ripples(false, p5, colorFromPalette, randomNumber); + this.ripples_random = ripples(true, p5, colorFromPalette, randomNumber); + this.blooming_petals = bloomingPetals(p5, getCurrentPalette, colorFromPalette); + this.clouds = clouds(p5, lerpColorFromPalette); + this.frosted_grid = frostedGrid(p5, getCurrentPalette, randomNumber); + this.starburst = starburst(p5, lerpColorFromPalette, randomColorFromPalette, randomNumber); + this.diamonds = diamonds(p5, lerpColorFromPalette, getInPreviewMode); + this.circles = circles(p5, lerpColorFromPalette); + this.sparkles = sparkles(p5, randomColorFromPalette, randomNumber); + this.text = text(p5, lerpColorFromPalette, colorFromHue, randomNumber, getInPreviewMode); + this.splatter = splatter(p5, randomColorFromPalette); + this.swirl = swirl(p5, randomColorFromPalette); + this.spiral = spiral(p5, lerpColorFromPalette); + this.lasers = lasers(p5, lerpColorFromPalette, getInPreviewMode); + this.quads = quads(p5, colorFromPalette); + this.kaleidoscope = kaleidoscope(p5, colorFromPalette); + this.snowflakes = snowflakes(p5, lerpColorFromPalette, getInPreviewMode); + this.fireworks = fireworks(p5, randomColorFromPalette, randomNumber); + this.stars = stars(p5, randomColorFromPalette, getInPreviewMode); + this.galaxy = galaxy(p5, randomColorFromPalette, randomNumber, getInPreviewMode); + this.growing_stars = growingStars(p5, colorFromPalette); + this.squiggles = squiggles(p5, lerpColorFromPalette); + this.music_wave = musicWave(p5, lerpColorFromPalette); + + // foreground + this.rain = rain(p5, randomNumber); + this.raining_tacos = rainingTacos(p5, randomNumber, getInPreviewMode); + this.pineapples = pineapples(p5, randomNumber, getInPreviewMode); + this.spotlight = spotlight(p5, randomNumber); + this.color_lights = colorLights(p5, randomNumber, randomColor); + this.smiling_poop = smilingPoop(p5, randomNumber, getInPreviewMode); + this.hearts_red = heartsRed(p5, randomNumber); + this.hearts_colorful = heartsColorful(p5, randomNumber, randomColor); + this.floating_rainbows = floatingRainbows(p5, randomNumber, getInPreviewMode); + this.bubbles = bubbles(p5, randomColor, getInPreviewMode); + this.exploding_stars = explodingStars(p5, randomNumber, randomColor, getInPreviewMode); + this.pizzas = pizzas(p5, randomNumber, getInPreviewMode); + this.smile_face = smileFace(p5, randomNumber, getInPreviewMode); + this.confetti = confetti(p5, randomColor, getInPreviewMode); + this.music_notes = musicNotes(p5, randomNumber, getInPreviewMode); + this.paint_drip = paintDrip(p5, lerpColorFromSpecificPalette, getInPreviewMode); + this.emojis = emojis(p5, randomNumber, getInPreviewMode); } setInPreviewMode(inPreviewMode) { diff --git a/src/effects/bloomingPetals.js b/src/effects/bloomingPetals.js new file mode 100644 index 00000000..1e993dff --- /dev/null +++ b/src/effects/bloomingPetals.js @@ -0,0 +1,58 @@ +const constants = require('../constants'); +const {hexToRgb} = require('../utils'); +const drawPetal = require('../shapes/petal'); + +// This effect is slightly modified from Poetry background effect 'blooming' +// https://github.com/code-dot-org/code-dot-org/blob/381e9b93f7cbd081738dfa7adbc9e7ce4e169a0c/apps/src/p5lab/poetry/commands/backgroundEffects.js#L245 +module.exports = function (p5, getCurrentPalette, colorFromPalette) { + return { + colorIndex: 0, + petals: [], + paletteLength: 0, + addPetalLayer: function (color, layer) { + for (let i = 0; i < 8; i++) { + this.petals.push({ + theta: 45 * i, + length: 10 + 140 * layer, + ...color, + }); + } + }, + init: function () { + this.paletteLength = constants.PALETTES[getCurrentPalette()].length; + this.petals = []; + // Initialize with enough petals to fill the screen - this is mostly + // useful so that preview shows what the background actually looks like. + // Increment from 3 down to 0 so that petals are layered correctly with + // bigger petals behind smaller petals. + for (let layer = 3; layer >= 0; layer--) { + const color = colorFromPalette(this.colorIndex); + this.addPetalLayer(hexToRgb(color), layer); + this.colorIndex = (this.colorIndex + 1) % this.paletteLength; + } + }, + draw: function () { + p5.push(); + p5.strokeWeight(2); + if (p5.World.frameCount % 70 === 0) { + const color = colorFromPalette(this.colorIndex); + this.addPetalLayer(hexToRgb(color), 0 /* layer */); + this.colorIndex = (this.colorIndex + 1) % this.paletteLength; + } + const petalWidth = 35; + this.petals.forEach(petal => { + // Multiply each component by 0.8 to have the stroke color be + // slightly darker than the fill color. + p5.stroke( + p5.color(petal.R * 0.8, petal.G * 0.8, petal.B * 0.8) + ); + p5.fill(p5.color(petal.R, petal.G, petal.B)); + drawPetal(p5, petal.length, petal.theta, petalWidth); + petal.theta = (petal.theta + 0.5) % 360; + petal.length += 2; + }); + this.petals = this.petals.filter(petal => petal.length < 700); + p5.pop(); + }, + }; +}; diff --git a/src/effects/bubbles.js b/src/effects/bubbles.js new file mode 100644 index 00000000..cdf8addb --- /dev/null +++ b/src/effects/bubbles.js @@ -0,0 +1,41 @@ +module.exports = function (p5, randomColor, getInPreviewMode) { + return { + bubble: [], + draw: function () { + const numBubblesToDraw = this.getPreviewCustomizations().numBubblesToDraw; + for (let i = 0; i < numBubblesToDraw; i++) { + let bubble = { + x: p5.random(-100, 400), + y: this.getPreviewCustomizations().y, + velocityX: p5.random(-2, 2), + size: p5.random(6, 12, 18), + color: randomColor(100, 50, 0.25), + }; + this.bubble.push(bubble); + } + + p5.noStroke(); + this.bubble.forEach(function (bubble) { + p5.push(); + p5.fill(bubble.color); + p5.translate(bubble.x, bubble.y); + p5.ellipse(0, 0, bubble.size, bubble.size); + let fallSpeed = p5.map(bubble.size, 6, 12, 1, 3); + bubble.y -= fallSpeed; + bubble.x += bubble.velocityX; + p5.pop(); + }); + this.bubble = this.bubble.filter(function (bubble) { + return bubble.y > 0; + }); + }, + reset: function () { + this.bubble = []; + }, + getPreviewCustomizations: function () { + return getInPreviewMode() ? + {numBubblesToDraw: 200, y: p5.random(-100, 400)} : + {numBubblesToDraw: 1, y: 410}; + } + }; +}; diff --git a/src/effects/circles.js b/src/effects/circles.js new file mode 100644 index 00000000..65d9bc4d --- /dev/null +++ b/src/effects/circles.js @@ -0,0 +1,22 @@ +module.exports = function (p5, lerpColorFromPalette) { + return { + hue: 0, + update: function () { + this.hue += 25; + }, + draw: function ({isPeak}) { + if (isPeak) { + this.update(); + } + p5.push(); + p5.noStroke(); + p5.ellipseMode(p5.CENTER); + p5.translate(200, 200); + for (let i = 5; i > -1; i--) { + p5.fill(lerpColorFromPalette(((this.hue + i * 10) % 360) / 360)); + p5.ellipse(0, 0, i * 100 + 75, i * 100 + 75); + } + p5.pop(); + }, + }; +}; diff --git a/src/effects/clouds.js b/src/effects/clouds.js new file mode 100644 index 00000000..0adee876 --- /dev/null +++ b/src/effects/clouds.js @@ -0,0 +1,47 @@ +const {getP5Color} = require('../utils'); + +// This effect is slightly modified from Poetry background effect 'clouds' +// https://github.com/code-dot-org/code-dot-org/blob/381e9b93f7cbd081738dfa7adbc9e7ce4e169a0c/apps/src/p5lab/poetry/commands/backgroundEffects.js#L368 +module.exports = function (p5, lerpColorFromPalette) { + return { + tileSize: 20, + tiles: [], + init: function () { + const noiseScale = 0.05; + this.tiles = []; + let xnoise = 0.01; + let ynoise = 0.01; + for (let x = 0; x < 400; x += this.tileSize) { + xnoise = 0.01; + for (let y = 0; y < 400; y += this.tileSize) { + this.tiles.push({ + x, + y, + xnoise, + ynoise, + }); + xnoise += noiseScale; + } + ynoise += noiseScale; + } + }, + draw: function () { + const speed = 0.015; + let backgroundAmount = 0; + p5.push(); + p5.noStroke(); + backgroundAmount += speed; + p5.background( + lerpColorFromPalette(backgroundAmount) + ); + this.tiles.forEach(tile => { + tile.alpha = p5.noise(tile.xnoise, tile.ynoise) * 255; + tile.xnoise += speed; + tile.ynoise += speed; + p5.fill(getP5Color(p5, '#ffffff', tile.alpha)); + p5.rect(tile.x, tile.y, this.tileSize, this.tileSize); + }); + p5.pop(); + }, + } +}; diff --git a/src/effects/colorCycle.js b/src/effects/colorCycle.js new file mode 100644 index 00000000..f652954d --- /dev/null +++ b/src/effects/colorCycle.js @@ -0,0 +1,14 @@ +module.exports = function (p5, lerpColorFromPalette) { + return { + color: 0, + update: function () { + this.color += 0.03; + }, + draw: function ({isPeak}) { + if (isPeak) { + this.update(); + } + p5.background(lerpColorFromPalette(this.color)); + }, + }; +}; diff --git a/src/effects/colorLights.js b/src/effects/colorLights.js new file mode 100644 index 00000000..006b2306 --- /dev/null +++ b/src/effects/colorLights.js @@ -0,0 +1,46 @@ +module.exports = function (p5, randomNumber, randomColor) { + return { + lights: [], + newLight: function (x, arc, offset) { + return { + x: x, + arc: arc, + offset: offset, + shift: randomNumber(0, 359), + color: randomColor(100, 50, 0.25), + }; + }, + init: function () { + if (this.lights.length) { + return; + } + this.lights.push(this.newLight(75, 25, -10)); + this.lights.push(this.newLight(100, 15, -15)); + this.lights.push(this.newLight(300, 15, 15)); + this.lights.push(this.newLight(325, 25, 10)); + }, + update: function () { + this.lights.forEach(function (light) { + light.color = randomColor(100, 50, 0.25); + }); + }, + draw: function ({isPeak, centroid}) { + if (isPeak) { + this.update(); + } + p5.noStroke(); + this.lights.forEach(function (light) { + p5.push(); + p5.fill(light.color); + p5.translate(light.x, -50); + p5.rotate( + Math.sin(p5.frameCount / 100 + light.shift + centroid / 2000) * + light.arc + + light.offset + ); + p5.triangle(0, 0, -75, 600, 75, 600); + p5.pop(); + }); + }, + }; +}; diff --git a/src/effects/confetti.js b/src/effects/confetti.js new file mode 100644 index 00000000..0372410b --- /dev/null +++ b/src/effects/confetti.js @@ -0,0 +1,49 @@ +module.exports = function (p5, randomColor, getInPreviewMode) { + return { + confetti: [], + draw: function () { + const numConfettiToDraw = this.getPreviewCustomizations().numConfettiToDraw; + for (let i = 0; i < numConfettiToDraw; i++) { + const spin = this.getPreviewCustomizations().spin; + let confetti = { + x: p5.random(-100, 400), + y: this.getPreviewCustomizations().y, + velocityX: p5.random(-2, 2), + size: p5.random(6, 12, 18), + // https://github.com/Automattic/node-canvas/issues/702 + // Bug with node-canvas prevents scaling with a value of 0, so spin initializes to 1 + spin: spin, + color: randomColor(255, 255, 100), + }; + + this.confetti.push(confetti); + } + + p5.noStroke(); + this.confetti.forEach(function (confetti) { + p5.push(); + p5.fill(confetti.color); + p5.translate(confetti.x, confetti.y); + const scaleX = p5.sin(confetti.spin); + p5.scale(scaleX, 1); + confetti.spin += 20; + p5.rect(0, 0, 4, confetti.size); + let fallSpeed = p5.map(confetti.size, 6, 12, 1, 3); + confetti.y += fallSpeed; + confetti.x += confetti.velocityX; + p5.pop(); + }); + this.confetti = this.confetti.filter(function (confetti) { + return confetti.y < 425; + }); + }, + reset: function () { + this.confetti = []; + }, + getPreviewCustomizations: function () { + return getInPreviewMode() ? + {numConfettiToDraw: 200, spin: p5.random(1, 80), y: p5.random(-100, 400)} : + {numConfettiToDraw: 1, spin: 1, y: -10}; + } + }; +}; diff --git a/src/effects/diamonds.js b/src/effects/diamonds.js new file mode 100644 index 00000000..07c37c2e --- /dev/null +++ b/src/effects/diamonds.js @@ -0,0 +1,30 @@ +module.exports = function (p5, lerpColorFromPalette, getInPreviewMode) { + return { + hue: 0, + update: function () { + this.hue += 25; + }, + draw: function ({isPeak, centroid}) { + if (isPeak) { + this.update(); + } + const centroidValue = this.getPreviewCustomizations().getCentroid(centroid); + p5.push(); + p5.rectMode(p5.CENTER); + p5.translate(200, 200); + p5.rotate(45); + p5.noFill(); + p5.strokeWeight(p5.map(centroidValue, 0, 4000, 0, 50)); + for (let i = 5; i > -1; i--) { + p5.stroke(lerpColorFromPalette(((this.hue + i * 10) % 360) / 360)); + p5.rect(0, 0, i * 100 + 50, i * 100 + 50); + } + p5.pop(); + }, + getPreviewCustomizations: function () { + return getInPreviewMode() ? + {getCentroid: () => 2000} : + {getCentroid: centroid => centroid}; + }, + }; +}; diff --git a/src/effects/disco.js b/src/effects/disco.js new file mode 100644 index 00000000..7bd07ed2 --- /dev/null +++ b/src/effects/disco.js @@ -0,0 +1,49 @@ +module.exports = function (p5, lerpColorFromPalette, randomNumber) { + return { + bg: undefined, + colors: [], + squaresPerSide: 4, + minColorChangesPerUpdate: 5, + maxColorChangesPerUpdate: 9, + init: function () { + if (this.colors.length) { + return; + } + // Alpha is ignored for this effect to avoid memory leaks with too many + // layers of alpha blending. + this.colors.length = this.squaresPerSide * this.squaresPerSide; + for (let i = 0; i < this.colors.length; i++) { + this.colors[i] = lerpColorFromPalette(p5.random(0, 1)); + } + }, + update: function () { + const numChanges = randomNumber( + this.minColorChangesPerUpdate, + this.maxColorChangesPerUpdate + ); + for (let i = 0; i < numChanges; i++) { + const loc = randomNumber(0, this.colors.length); + this.colors[loc] = lerpColorFromPalette(p5.random(0, 1)); + } + }, + draw: function ({isPeak}) { + if (isPeak) { + this.update(); + } + p5.push(); + p5.noStroke(); + const squareWidth = p5.width / this.squaresPerSide; + const squareHeight = p5.height / this.squaresPerSide; + for (let i = 0; i < this.colors.length; i++) { + p5.fill(this.colors[i]); + p5.rect( + (i % this.squaresPerSide) * squareWidth, + Math.floor(i / this.squaresPerSide) * squareHeight, + squareWidth, + squareHeight + ); + } + p5.pop(); + }, + }; +}; diff --git a/src/effects/discoBall.js b/src/effects/discoBall.js new file mode 100644 index 00000000..83c33494 --- /dev/null +++ b/src/effects/discoBall.js @@ -0,0 +1,104 @@ +const drawSparkle = require("../shapes/sparkle"); + +module.exports = function (p5, lerpColorFromPalette, colorFromPalette) { + return { + stars: [], + globe: function (u, v) { + u = p5.constrain(u, -90, 90); + return { + x: (1 + p5.sin(u) * p5.sin(v)) * 45 + 155, + y: (1 + p5.cos(v)) * 45 + 10, + }; + }, + quad: function (i, j, faceSize, rotation = 0) { + const k = ((i + rotation) % 360) - 180; + if (k < -90 - faceSize || k > 90) { + return; + } + const color = lerpColorFromPalette(p5.noise(i, j, p5.frameCount / 70)); + const highlight = 50 * p5.pow(p5.cos(k), 2); + const brightness = + p5.noise(i, j, p5.frameCount / 50) * 150 + 100 + highlight; + p5.fill(p5.lerpColor(color, p5.color(brightness), brightness / 255)); + const a = this.globe(k, j); + const b = this.globe(k + faceSize, j); + const c = this.globe(k + faceSize, j + faceSize); + const d = this.globe(k, j + faceSize); + p5.quad(a.x, a.y, b.x, b.y, c.x, c.y, d.x, d.y); + }, + init: function () { + this.stars.length = 0; + + for (let i = 0; i < 75; i++) { + this.stars.push({ + x: p5.random(0, 400), + y: p5.random(0, 250), + color: p5.lerpColor( + lerpColorFromPalette(p5.random()), + p5.color('#fff'), + 0.75 + ), + }); + } + }, + draw: function () { + p5.noFill(); + // Draw a horizontal gradient of the palette colors to the background + let ctx = p5._renderer.drawingContext; + ctx.save(); + let gradient = ctx.createLinearGradient(425, 425, 425, 0); + // Initialize first color stop so colors loop + let color = colorFromPalette(0); + gradient.addColorStop(0, color); + for (let i = 0; i < 5; i++) { + let color = colorFromPalette(i); + gradient.addColorStop((5 - i) / 5, color.toString()); + } + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 425, 425); + ctx.restore(); + + p5.noStroke(); + + for (const star of this.stars) { + const distanceFromCenter = 200 - star.x; + const opacity = p5.constrain(p5.cos(distanceFromCenter / 2), 0, 4); + const heightFade = p5.constrain(250 - star.y, 0, 500); + p5.push(); + p5.translate(star.x, star.y); + const sparkle = p5.constrain( + p5.noise(star.x / 50, star.y / 50, p5.frameCount / 50) + 0.4, + 0, + 1 + ); + p5.drawingContext.globalAlpha = opacity * (heightFade / 100) * 0.85; + p5.scale(1 / sparkle); + drawSparkle(p5._renderer.drawingContext, star.color); + p5.pop(); + + // Move the star to the left. + star.x -= 4.5 - opacity * 1.5; + + // If we've gone off-screen, loop around to the right. + if (star.x < 0) { + star.x = 400; + } + } + + p5.noiseDetail(50, 0.5); + p5.stroke('#999'); + p5.strokeWeight(2); + p5.line(200, 0, 200, 15); + p5.strokeWeight(0.25); + + const step = 20; + for (let i = 0; i <= 360; i += step) { + for (let j = 0; j < 180; j += step) { + p5.push(); + this.quad(i, j, step, p5.frameCount * 2); + p5.pop(); + } + } + }, + }; +}; diff --git a/src/effects/emojis.js b/src/effects/emojis.js new file mode 100644 index 00000000..b354d8cc --- /dev/null +++ b/src/effects/emojis.js @@ -0,0 +1,96 @@ +const drawLovestruck = require('../shapes/lovestruck'); +const drawSmiley = require('../shapes/smiley'); +const drawStarstruck = require('../shapes/starstruck'); +const drawTickled = require('../shapes/tickled'); +const drawWink = require('../shapes/wink'); + +module.exports = function (p5, randomNumber, getInPreviewMode) { + return { + emojiList: [], + emojiTypes: [], + + init: function () { + this.imageLovestruck = p5.createGraphics(100, 100); + this.imageLovestruck.scale(3); + drawLovestruck(this.imageLovestruck.drawingContext); + this.emojiTypes.push(this.imageLovestruck); + + this.imageSmiley = p5.createGraphics(100, 100); + this.imageSmiley.scale(3); + drawSmiley(this.imageSmiley.drawingContext, 1.0); + this.emojiTypes.push(this.imageSmiley); + + this.imageStarstruck = p5.createGraphics(100, 100); + this.imageStarstruck.scale(3); + drawStarstruck(this.imageStarstruck.drawingContext); + this.emojiTypes.push(this.imageStarstruck); + + this.imageTickled = p5.createGraphics(100, 100); + this.imageTickled.scale(3); + drawTickled(this.imageTickled.drawingContext); + this.emojiTypes.push(this.imageTickled); + + this.imageWink = p5.createGraphics(100, 100); + this.imageWink.scale(3); + drawWink(this.imageWink.drawingContext); + this.emojiTypes.push(this.imageWink); + }, + + draw: function () { + this.getPreviewCustomizations().addEmojis(); + + for (let i = 0; i < this.emojiList.length; ++i) { + const emoji = this.emojiList[i]; + emoji.y += p5.pow(emoji.size, 0.25); // emoji falls at a rate fourth root to its size + if (emoji.y > p5.height * 1.2) { + // if the emoji has fallen past 120% of the screen + this.emojiList.splice(i, 1); + } + p5.push(); + p5.drawingContext.drawImage( + emoji.image.elt, + emoji.x, + emoji.y, + emoji.size, + emoji.size + ); + p5.pop(); + } + }, + reset: function () { + this.emojiList = []; + }, + getPreviewCustomizations: function () { + if (getInPreviewMode()) { + const addEmojisPreview = () => { + if (this.emojiList.length) { + return; + } + + for (let i = 0; i < 12; i++) { + this.emojiList.push({ + x: randomNumber(0, 350), + y: randomNumber(0, 350), + size: randomNumber(50, 90), + image: this.emojiTypes[randomNumber(0, 4)], + }); + } + }; + return {addEmojis: addEmojisPreview}; + } else { + const addEmojisDefault = () => { + if (p5.frameCount % 10 === 0) { + // generate new emoji every 10 frames + this.emojiList.push({ + x: randomNumber(0, 350), + y: -50, + size: randomNumber(50, 90), + image: this.emojiTypes[randomNumber(0, 4)], + }); + } + }; + return {addEmojis: addEmojisDefault}; + } + }, + }; +}; diff --git a/src/effects/explodingStars.js b/src/effects/explodingStars.js new file mode 100644 index 00000000..bb023b9c --- /dev/null +++ b/src/effects/explodingStars.js @@ -0,0 +1,43 @@ +const drawStar = require('../shapes/star'); + +module.exports = function (p5, randomNumber, randomColor, getInPreviewMode) { + return { + stars: [], + init: function () { + this.stars = []; + for (let i = 0; i < 100; i++) { + let theta = p5.random(0, 360); + let velocity = p5.random(4, 12); + + this.stars.push({ + color: randomColor(255, 255, 100), + x: this.getPreviewCustomizations().x, + y: this.getPreviewCustomizations().y, + dx: velocity * p5.cos(theta), + dy: velocity * p5.sin(theta), + }); + } + }, + draw: function () { + p5.angleMode(p5.DEGREES); + p5.noStroke(); + if (this.stars.length === 0) { + this.init(); + } + this.stars.forEach(star => { + p5.fill(star.color); + drawStar(p5, star.x, star.y, 3, 9, 5); + star.x += star.dx; + star.y += star.dy; + }); + this.stars = this.stars.filter( + star => star.x > -10 && star.x < 410 && star.y > -10 && star.y < 410 + ); + }, + getPreviewCustomizations: function () { + return getInPreviewMode() ? + {x: randomNumber(0, 400), y: randomNumber(0, 400)} : + {x: 200, y: 200}; + } + }; +}; diff --git a/src/effects/fireworks.js b/src/effects/fireworks.js new file mode 100644 index 00000000..f9e27b32 --- /dev/null +++ b/src/effects/fireworks.js @@ -0,0 +1,139 @@ +const drawSparkle = require('../shapes/sparkle'); + +module.exports = function (p5, randomColorFromPalette, randomNumber) { + return { + particles: [], + minExplosion: 20, + maxExplosion: 50, + minPotential: 200, + maxPotential: 300, + buffer: null, + + makeParticle: function (type, pos, vel, color, potential) { + return { + type: type, + pos: pos, + vel: vel, + gravity: p5.createVector(0.0, 0.1), + potential: potential, + acc: p5.createVector(0, 0), + color: color, + alpha: 1, + update: function () { + this.acc.add(this.gravity); + this.vel.add(this.acc); + this.pos.add(this.vel); + this.acc.mult(0, 0); + }, + }; + }, + + init: function () { + if (this.buffer) { + return; + } + // We get the tracer effect by writing frames to a + // off-screen buffer that has a transparent background. + this.buffer = p5.createGraphics(p5.width, p5.height); + }, + + draw: function () { + p5.background(0); + this.buffer.background(0, 25); + + p5.push(); + this.drawParticles(); + + // Copy the off-screen buffer to the canvas. + p5.scale(1 / p5.pixelDensity()); + p5.drawingContext.drawImage(this.buffer.elt, 0, 0); + + p5.pop(); + + this.particles = this.nextParticles(); + }, + + drawParticles: function () { + for (var i = 0; i < this.particles.length; i++) { + let p = this.particles[i]; + p.update(); + + this.buffer.push(); + if (p.type === 'rocket') { + this.buffer.strokeWeight(3); + this.buffer.stroke(p.color); + this.buffer.point(p.pos.x, p.pos.y); + } else if (p.type === 'particle') { + this.buffer.translate(p.pos.x, p.pos.y); + this.buffer.drawingContext.globalAlpha = p.alpha; + p.alpha = p5.constrain(p.alpha - 0.02, 0, 1); + drawSparkle(this.buffer.drawingContext, p.color); + } + this.buffer.pop(); + } + }, + + nextParticles: function () { + let ret = []; + + // total potential is the number of particles active, or the number represented + // in unexploded rockets. This is how we manage total number of objects + var totalPotential = 0; + for (var i = 0; i < this.particles.length; i++) { + let p = this.particles[i]; + + if (p.type === 'rocket') { + // explode a rocket when it reaches it peak height + if (p.vel.y <= 0) { + ret.push(p); + } else { + ret = ret.concat(this.explode(p)); + } + + // the rocket exploded to its potential or its still waiting + totalPotential += p.potential; + } else if (p.type === 'particle') { + // remove things when they leave the window, except allow particles + // to fall back down into the view from above + if (p.pos.x > 0 && p.pos.x < p5.width && p.pos.y < p5.height) { + ret.push(p); + totalPotential += p.potential; + } + } + } + + // make sure the total potential for particles is between the min and max potential + if (totalPotential < this.minPotential) { + // fire rockets until we fill the potential + while (totalPotential < this.maxPotential) { + let p = this.makeParticle( + 'rocket', + p5.createVector(randomNumber(0, p5.height), p5.width), + p5.createVector(0, p5.random(-9, -7)), + randomColorFromPalette(), + p5.random(this.minExplosion, this.maxExplosion) + ); + totalPotential += p.potential; + ret.push(p); + } + } + return ret; + }, + + explode: function (p) { + let ret = []; + for (var i = 0; i < p.potential; i++) { + ret.push( + this.makeParticle( + 'particle', + p5.createVector(p.pos.x, p.pos.y), + p5.createVector(p5.random(-5, 5), p5.random(-5, 5)), + p.color, + 1 + ) + ); + } + return ret; + }, + }; +}; diff --git a/src/effects/floatingRainbows.js b/src/effects/floatingRainbows.js new file mode 100644 index 00000000..7b66b1bb --- /dev/null +++ b/src/effects/floatingRainbows.js @@ -0,0 +1,58 @@ +const drawRainbow = require('../shapes/rainbow'); + +module.exports = function (p5, randomNumber, getInPreviewMode) { + return { + rainbows: [], + init: function () { + if (this.rainbows.length) { + return; + } + + for (let i = 0; i < 15; i++) { + this.rainbows.push({ + x: randomNumber(10, 390), + y: this.getPreviewCustomizations().y, + rot: randomNumber(0, 359), + speed: 2, + size: randomNumber(1.5, 3), + }); + } + this.image = p5.createGraphics(175, 100); + this.image.scale(3); + drawRainbow(this.image.drawingContext); + }, + draw: function (context) { + const centroid = this.getPreviewCustomizations().getCentroid(context); + + for (let i = 0; i < this.rainbows.length; i++) { + p5.push(); + const rainbows = this.rainbows[i]; + let scale = p5.map(centroid, 5000, 8000, 0, rainbows.size); + scale = p5.constrain(scale, 0, 3); + p5.translate(rainbows.x, rainbows.y); + p5.scale(scale / (2 * p5.pixelDensity())); + p5.image(this.image); + rainbows.y -= rainbows.speed; + if (rainbows.y < -25) { + rainbows.x = randomNumber(10, 390); + rainbows.y = 450; + } + p5.pop(); + } + }, + reset: function () { + this.rainbows = []; + }, + getPreviewCustomizations: function () { + return getInPreviewMode() ? + { + y: randomNumber(0, 400), + getCentroid: () => 6500, + } : + { + y: randomNumber(400, 800), + getCentroid: context => context.centroid, + }; + }, + }; +}; diff --git a/src/effects/flowers.js b/src/effects/flowers.js new file mode 100644 index 00000000..62255eb0 --- /dev/null +++ b/src/effects/flowers.js @@ -0,0 +1,33 @@ +module.exports = function (p5, lerpColorFromPalette) { + return { + hue: 0, + + drawFlower: function (num_petals, color) { + p5.fill(color); + for (let i = 0; i < num_petals; i++) { + p5.rotate(360 / num_petals); + p5.ellipse(0, 30, 20, 80); + } + }, + + draw: function ({isPeak}) { + if (isPeak) { + this.hue += 25; + } + p5.push(); + p5.noStroke(); + p5.translate(200, 200); + p5.angleMode(p5.DEGREES); + for (let i = 9; i > -1; i--) { + p5.push(); + p5.scale(i); + this.drawFlower( + 8, + lerpColorFromPalette(((this.hue + i * 10) % 360) / 360) + ); + p5.pop(); + } + p5.pop(); + }, + }; +}; diff --git a/src/effects/frostedGrid.js b/src/effects/frostedGrid.js new file mode 100644 index 00000000..e48a05d8 --- /dev/null +++ b/src/effects/frostedGrid.js @@ -0,0 +1,37 @@ +const constants = require('../constants'); +const {hexToRgb} = require('../utils'); +const drawFrostedGrid = require('../shapes/frostedGrid'); + +// This effect is slightly modified from Poetry background effect 'fadeColors' +// https://github.com/code-dot-org/code-dot-org/blob/381e9b93f7cbd081738dfa7adbc9e7ce4e169a0c/apps/src/p5lab/poetry/commands/backgroundEffects.js#L181 +module.exports = function (p5, getCurrentPalette, randomNumber) { + return { + anchors: [], + circles: [], + spacing: 20, + init: function () { + this.anchors = []; + this.circles = []; + const paletteColors = constants.PALETTES[getCurrentPalette()]; + paletteColors.forEach(color => { + this.anchors.push({ + x: randomNumber(0, 400), + y: randomNumber(0, 400), + velocityX: randomNumber(-3, 3), + velocityY: randomNumber(-3, 3), + ...hexToRgb(color), + }); + }); + for (let x = 0; x < 420; x += this.spacing) { + for (let y = 0; y < 420; y += this.spacing) { + this.circles.push({x, y, red: 0, green: 0, blue: 0}); + } + } + }, + draw: function () { + p5.push(); + drawFrostedGrid(p5, this.anchors, this.circles, this.spacing); + p5.pop(); + }, + }; +}; diff --git a/src/effects/galaxy.js b/src/effects/galaxy.js new file mode 100644 index 00000000..5add571b --- /dev/null +++ b/src/effects/galaxy.js @@ -0,0 +1,58 @@ +module.exports = function (p5, randomColorFromPalette, randomNumber, getInPreviewMode) { + return { + asteroid: [], + draw: function () { + p5.background('black'); + const numAsteroidsToDraw = this.getPreviewCustomizations().numAsteroidsToDraw; + for (let i = 0; i < numAsteroidsToDraw; i++) { + let asteroid = { + x: this.getPreviewCustomizations().x, + y: this.getPreviewCustomizations().y, + velocity: p5.createVector(0, 1).rotate(p5.random(0, 360)), + size: this.getPreviewCustomizations().size, + color: randomColorFromPalette(), + }; + this.asteroid.push(asteroid); + } + p5.noStroke(); + + this.asteroid.forEach(asteroid => { + p5.push(); + p5.fill(asteroid.color); + p5.translate(asteroid.x, asteroid.y); + p5.ellipse(0, 0, asteroid.size, asteroid.size); + let speedMultiplier = p5.pow(asteroid.size, 2) / 2; + asteroid.x += this.getPreviewCustomizations().getMovementDistance(asteroid.velocity.x, speedMultiplier); + asteroid.y += this.getPreviewCustomizations().getMovementDistance(asteroid.velocity.y, speedMultiplier); + asteroid.size += 0.1; + p5.pop(); + }); + this.asteroid = this.asteroid.filter(function (asteroid) { + if (asteroid.x < -5 || asteroid.x > 405 || asteroid.y < -5 || asteroid.y > 405) { + return false; + } + return true; + }); + }, + reset: function () { + this.asteroid = []; + }, + getPreviewCustomizations: function () { + return getInPreviewMode() ? + { + numAsteroidsToDraw: 200, + size: 3, + x: randomNumber(0, 400), + y: randomNumber(0, 400), + getMovementDistance: () => 0, + } : + { + numAsteroidsToDraw: 3, + size: 0.01, + x: 200, + y: 200, + getMovementDistance: (dimension, multiplier) => dimension * multiplier + }; + } + }; +}; diff --git a/src/effects/growingStars.js b/src/effects/growingStars.js new file mode 100644 index 00000000..c10882ac --- /dev/null +++ b/src/effects/growingStars.js @@ -0,0 +1,36 @@ +const drawStar = require('../shapes/star'); + +module.exports = function (p5, colorFromPalette) { + return { + stars: [], + colorIndex: 0, + starSpacing: 30, + numStars: 9, + + init: function () { + p5.angleMode(p5.DEGREES); + this.colorIndex = 0; + this.stars = []; + for (var i = 0; i < this.numStars; i++) { + this.stars.push({ + size: this.starSpacing * (this.numStars - i), + colorIndex: this.colorIndex, + }); + this.colorIndex++; + } + }, + + draw: function () { + for (let star of this.stars) { + p5.fill(colorFromPalette(star.colorIndex)); + drawStar(p5, 200, 200, star.size, star.size * 2.5, 5); + star.size += 1; + } + if (this.stars[0].size > this.starSpacing * this.numStars) { + this.stars.shift(); + this.stars.push({size: 0, colorIndex: this.colorIndex}); + this.colorIndex++; + } + }, + }; +}; diff --git a/src/effects/heartsColorful.js b/src/effects/heartsColorful.js new file mode 100644 index 00000000..236a4abc --- /dev/null +++ b/src/effects/heartsColorful.js @@ -0,0 +1,41 @@ +const drawHeart = require('../shapes/heart'); + +module.exports = function (p5, randomNumber, randomColor) { + return { + heartList: [], + init: function () { + if (this.heartList.length) { + return; + } + for (let i = 0; i < 10; i++) { + this.heartList.push({ + x: randomNumber(10, 390), + y: randomNumber(10, 390), + rot: randomNumber(0, 359), + life: randomNumber(10, 120), + color: randomColor(100, 50, 0.25), + }); + } + }, + draw: function () { + for (let i = 0; i < this.heartList.length; i++) { + p5.push(); + const heart = this.heartList[i]; + p5.translate(heart.x, heart.y); + p5.rotate(heart.rot); + p5.scale(heart.life / 20); + drawHeart(p5._renderer.drawingContext, heart.color); + heart.life--; + if (heart.life < 0) { + heart.x = randomNumber(10, 390); + heart.y = randomNumber(10, 390); + heart.life = randomNumber(10, 120); + } + p5.pop(); + } + }, + reset: function () { + this.heartList = []; + } + }; +}; diff --git a/src/effects/heartsRed.js b/src/effects/heartsRed.js new file mode 100644 index 00000000..c24f2773 --- /dev/null +++ b/src/effects/heartsRed.js @@ -0,0 +1,40 @@ +const drawHeart = require('../shapes/heart'); + +module.exports = function (p5, randomNumber) { + return { + heartList: [], + init: function () { + if (this.heartList.length) { + return; + } + for (let i = 0; i < 10; i++) { + this.heartList.push({ + x: randomNumber(10, 390), + y: randomNumber(10, 390), + rot: randomNumber(0, 359), + life: randomNumber(10, 120), + color: p5.rgb(255, 0, 0, 0.5), + }); + } + }, + draw: function () { + for (const heart of this.heartList) { + p5.push(); + p5.translate(heart.x, heart.y); + p5.rotate(heart.rot); + p5.scale(heart.life / 20); + drawHeart(p5._renderer.drawingContext, heart.color); + heart.life--; + if (heart.life < 0) { + heart.x = randomNumber(10, 390); + heart.y = randomNumber(10, 390); + heart.life = randomNumber(10, 120); + } + p5.pop(); + } + }, + reset: function () { + this.heartList = []; + } + }; +}; diff --git a/src/effects/higherPower.js b/src/effects/higherPower.js new file mode 100644 index 00000000..a2628a95 --- /dev/null +++ b/src/effects/higherPower.js @@ -0,0 +1,76 @@ +const constants = require("../constants"); + +module.exports = function (p5, getCurrentPalette, extraImages) { + return { + init: function () {}, + draw: function () { + // The symbols are arranged to roughly fill a circle. These are [x,y] offset pairs. + const offsets = [ + [0, 270], + [61, 112], + [164, 1], + [312, 1], + [428, 66], + [591, 153], + [603, 323], + [491, 502], + [369, 502], + [237, 542], + [61, 438], + [200, 134], + [341, 173], + [473, 215], + [483, 340], + [353, 333], + [193, 419], + [141, 255], + [242, 248], + ]; + + let ctx = p5._renderer.drawingContext; + + ctx.save(); + let gradient = ctx.createLinearGradient(425, 425, 425, 0); + gradient.addColorStop( + 1, + constants.HIGHER_POWER_COLORS[getCurrentPalette()][0] + ); + gradient.addColorStop( + 0, + constants.HIGHER_POWER_COLORS[getCurrentPalette()][1] + ); + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, 425, 425); + ctx.restore(); + + p5.push(); + p5.translate(p5.width / 2, p5.height / 2); + p5.imageMode(p5.CENTER); + p5.rotate(p5.frameCount); + p5.scale(1.7); + extraImages['higherPower'].drawFrame(19, 0, 0); + p5.pop(); + + // There is a low frequency oscillation between equal-size symbols and + // different-size symbols. + const scaleContribution = Math.sin(p5.frameCount / 200); + + offsets.forEach(function (offset, symbolIndex) { + p5.push(); + p5.translate(p5.width / 2, p5.height / 2); + p5.imageMode(p5.CENTER); + p5.rotate(-p5.frameCount * 3); + p5.translate(offset[0] * 0.4 - 120, offset[1] * 0.4 - 120); + p5.rotate(p5.frameCount * 5); + p5.scale( + 0.27 + + (scaleContribution * + Math.sin(p5.frameCount / 100 + symbolIndex * 40)) / + 3 + ); + extraImages['higherPower'].drawFrame(symbolIndex, 0, 0); + p5.pop(); + }); + }, + }; +}; diff --git a/src/effects/kaleidoscope.js b/src/effects/kaleidoscope.js new file mode 100644 index 00000000..583f5e9e --- /dev/null +++ b/src/effects/kaleidoscope.js @@ -0,0 +1,123 @@ +module.exports = function (p5, colorFromPalette) { + return { + init: function () { + if (this.shapes) { + return; + } + + this.h = (Math.sqrt(3) / 2) * 100; + + this.shapes = p5.createGraphics(100, Math.ceil(this.h)); + this.shapes.noStroke(); + this.shapes.angleMode(p5.DEGREES); + + this.hex = p5.createGraphics(200, 200); + this.hex.angleMode(p5.DEGREES); + }, + blitHex: function () { + this.hex.push(); + this.hex.clear(); + this.hex.translate(100, 100); + this.hex.push(); + this.hex.scale(1 / p5.pixelDensity()); + this.hex.rotate(30); + for (let i = 0; i < 3; i++) { + this.hex.drawingContext.drawImage( + this.shapes.elt, + -50 * p5.pixelDensity(), + 0 + ); + this.hex.scale(-1, 1); + this.hex.rotate(60); + this.hex.drawingContext.drawImage( + this.shapes.elt, + -50 * p5.pixelDensity(), + 0 + ); + this.hex.rotate(60); + this.hex.scale(-1, 1); + } + this.hex.pop(); + this.hex.pop(); + }, + row: function (n) { + p5.push(); + for (let i = 0; i < n; i++) { + p5.push(); + p5.scale(1 / p5.pixelDensity()); + p5.drawingContext.drawImage( + this.hex.elt, + -100 * p5.pixelDensity(), + -100 * p5.pixelDensity() + ); + p5.pop(); + p5.translate(this.h * 2, 0); + } + p5.pop(); + }, + draw: function () { + p5.background(colorFromPalette(2)); + + const ctx = this.shapes.drawingContext; + ctx.save(); + ctx.beginPath(); + ctx.moveTo(50, 0); + ctx.lineTo(100, this.h); + ctx.lineTo(0, this.h); + ctx.clip(); + this.shapes.clear(); + this.shapes.rotate(p5.frameCount); + this.shapes.fill(colorFromPalette(0)); + this.shapes.rect(20, 20, 50, 50); + this.shapes.fill(colorFromPalette(2)); + this.shapes.triangle(0, 10, 80, 90, 0, 100); + this.shapes.fill(colorFromPalette(1)); + this.shapes.triangle(20, 0, 50, 30, 30, 60); + this.shapes.fill(colorFromPalette(4)); + this.shapes.ellipse(100, 50, 80); + this.shapes.fill(colorFromPalette(1)); + this.shapes.ellipse(-50, -50, 50); + this.shapes.fill(colorFromPalette(5)); + this.shapes.ellipse(-40, -46, 20); + this.shapes.fill(colorFromPalette(0)); + this.shapes.triangle(-60, 0, -30, -40, -30, 0); + this.shapes.fill(colorFromPalette(3)); + this.shapes.rect(-45, 0, 40, 300); + this.shapes.rotate(17); + this.shapes.fill(colorFromPalette(4)); + this.shapes.rect(30, 40, 10, 40); + this.shapes.rotate(37); + this.shapes.fill(colorFromPalette(6)); + this.shapes.rect(30, 40, 20, 40); + this.shapes.rotate(180); + this.shapes.fill(colorFromPalette(0)); + this.shapes.triangle(10, 20, 80, 90, 0, 100); + this.shapes.translate(20, 0); + this.shapes.rotate(20); + this.shapes.fill(colorFromPalette(3)); + this.shapes.rect(0, 0, 20, 200); + ctx.restore(); + + p5.push(); + this.blitHex(); + p5.imageMode(p5.CENTER); + + p5.translate(200, 200); + p5.rotate(p5.frameCount); + p5.scale(0.8); + + p5.translate(this.h * -2, -300); + this.row(3); + p5.translate(-this.h, 150); + this.row(4); + p5.translate(-this.h, 150); + this.row(5); + p5.translate(this.h, 150); + this.row(4); + p5.translate(this.h, 150); + this.row(3); + + p5.pop(); + }, + }; +}; diff --git a/src/effects/lasers.js b/src/effects/lasers.js new file mode 100644 index 00000000..bc870737 --- /dev/null +++ b/src/effects/lasers.js @@ -0,0 +1,59 @@ +module.exports = function (p5, lerpColorFromPalette, getInPreviewMode) { + return { + laser: [], + init: function () { + this.laser.length = 0; + }, + draw: function () { + p5.background('black'); + if (this.laser.length < 32) { + const numLasersToDraw = this.getPreviewCustomizations().numLasersToDraw; + for (let i = 0; i < numLasersToDraw; i++) { + let laser = { + y: this.getPreviewCustomizations().getY(i), + color: this.getPreviewCustomizations().getColor(i) + }; + this.laser.push(laser); + } + } + p5.push(); + p5.translate(200, 180); + for (const [index, laser] of this.laser.entries()) { + let x = this.getPreviewCustomizations().getX(index); + if (x < 0) { + x *= -1; + } + const angle = p5.atan2(laser.y, x); + p5.stroke(laser.color); + p5.line(0, 0, p5.sin(angle) * 300, p5.cos(angle) * 300); + laser.y = laser.y - 100; + if (laser.y <= -1400) { + laser.y = 1750; + } + } + p5.pop(); + }, + reset: function () { + this.laser = []; + }, + // Note to future readers: at the time of writing, + // this implementation felt particularly hacky relative to other preview customizations. + // It's more challenging than many others, because the effect is "less random" than many other previews. + // Definitely open to alternative implementations as time allows! + getPreviewCustomizations: function () { + return getInPreviewMode() ? + { + numLasersToDraw: 32, + getY: iterationNum => 1750 - (iterationNum * 100), + getColor: iterationNum => lerpColorFromPalette(iterationNum / 16), + getX: iterationNum => 200 * p5.sin(iterationNum), + } : + { + numLasersToDraw: 1, + getY: () => 1750, + getColor: () => lerpColorFromPalette(p5.frameCount / 16), + getX: () => 200 * p5.sin(p5.frameCount), + }; + }, + }; +}; diff --git a/src/effects/musicNotes.js b/src/effects/musicNotes.js new file mode 100644 index 00000000..90eedf6d --- /dev/null +++ b/src/effects/musicNotes.js @@ -0,0 +1,52 @@ +const drawMusicNote = require('../shapes/musicNote'); + +module.exports = function (p5, randomNumber, getInPreviewMode) { + return { + notes: [], + init: function () { + if (this.notes.length) { + return; + } + for (let i = 0; i < 20; i++) { + this.notes.push({ + x: randomNumber(10, 390), + y: this.getPreviewCustomizations().y, + rot: randomNumber(0, 359), + speed: 2, + size: randomNumber(1.5, 3), + }); + } + this.image = p5.createGraphics(70, 50); + this.image.scale(4); + drawMusicNote(this.image.drawingContext); + }, + draw: function (context) { + const centroid = this.getPreviewCustomizations().getCentroid(context); + for (let i = 0; i < this.notes.length; i++) { + p5.push(); + const notes = this.notes[i]; + let scale = p5.map(centroid, 5000, 8000, 0, notes.size); + scale = p5.constrain(scale, 0, 3); + p5.translate(notes.x, notes.y); + p5.rotate(notes.rot); + p5.scale(scale / (4 * p5.pixelDensity())); + p5.drawingContext.drawImage(this.image.elt, 0, 0); + notes.y += notes.speed; + notes.rot++; + if (notes.y > 410) { + notes.x = randomNumber(10, 390); + notes.y = -50; + } + p5.pop(); + } + }, + reset: function () { + this.notes = []; + }, + getPreviewCustomizations: function () { + return getInPreviewMode() ? + {y: randomNumber(0, 390), getCentroid: () => 6500} : + {y: randomNumber (-400, 0), getCentroid: context => context.centroid}; + }, + }; +}; diff --git a/src/effects/musicWave.js b/src/effects/musicWave.js new file mode 100644 index 00000000..70c331a3 --- /dev/null +++ b/src/effects/musicWave.js @@ -0,0 +1,30 @@ +module.exports = function (p5, lerpColorFromPalette) { + return { + inc: 360 / 15, + heightFactor: 1, + heightDivider: 200, + yLoc: 300, + lineWidth: p5.width / 80, + draw: function (context) { + const centroid = context.centroid; + let scale = p5.map(centroid, 5000, 8000, 0, 250); + let angle = 0; + p5.background('black'); + for (let i = 0; i < p5.width; i += this.lineWidth) { + p5.stroke(lerpColorFromPalette(i / p5.width)); + let amplitude = Math.abs( + scale * (this.heightFactor / this.heightDivider) * p5.cos(angle) + ); + let yInitial = this.yLoc - amplitude; + let yFinal = this.yLoc + amplitude; + p5.line(i, yInitial, i, yFinal); + if (i < p5.width / 2) { + this.heightFactor++; + } else { + this.heightFactor--; + } + angle += this.inc; + } + }, + }; +}; diff --git a/src/effects/paintDrip.js b/src/effects/paintDrip.js new file mode 100644 index 00000000..86ee4f84 --- /dev/null +++ b/src/effects/paintDrip.js @@ -0,0 +1,102 @@ +module.exports = function (p5, lerpColorFromSpecificPalette, getInPreviewMode) { + return { + current_drip: 0, + current_drip_height: 0, + crayons: [], + start_width: 15, + start_height: 30, + dripping_up: false, + drip_diameter: 20, + drip_speed: 7, + + reset: function () { + this.init(); + this.dripping_up = false; + }, + init: function () { + // Reset values + this.current_drip = 0; + this.current_drip_height = 0; + this.crayons = []; + + this.crayons.push({maxHeight: p5.random(30, 200), startFrame: 0}); + for (let i = 0; i < 17; i++) { + this.crayons.push({maxHeight: 0, startFrame: 0}); + } + }, + draw: function () { + for (let i = 0; i < this.crayons.length; i++) { + let c = lerpColorFromSpecificPalette('neon', i / this.crayons.length); + p5.fill(c); + p5.noStroke(); + let rectHeight = this.getPreviewCustomizations().getRectHeight(); + + // Drip is to the left of moving drip and should be stationary at full height + if (i < this.current_drip) { + rectHeight = this.crayons[i].maxHeight; + // Drip is currently moving + } else if (i === this.current_drip) { + //Calculate height with regard to direction of movement + if (this.dripping_up) { + rectHeight = + this.crayons[i].maxHeight - + (p5.frameCount - this.crayons[i].startFrame) * this.drip_speed; + } else { + rectHeight = + (p5.frameCount - this.crayons[i].startFrame) * this.drip_speed + + this.start_height; + } + this.current_drip_height = rectHeight; + } + //Draw each drip with a rectangle and ellipse + p5.rect(22 * i + 7, 0, this.start_width, rectHeight); + p5.ellipse( + 22 * i + this.start_width, + rectHeight, + this.drip_diameter, + this.drip_diameter + ); + } + + // Check if the current drip is 'done' + if ( + (!this.dripping_up && + this.current_drip_height >= + this.crayons[this.current_drip].maxHeight) || + (this.dripping_up && this.current_drip_height <= 30) + ) { + if ( + !this.dripping_up && + this.current_drip === this.crayons.length - 1 + ) { + // The rightmost drip is 'done' dripping down, switch to dripping up. + this.dripping_up = true; + this.current_drip_height = + this.crayons[this.current_drip].maxHeight; + } else if (this.dripping_up && this.current_drip === 0) { + // The leftmost drip is 'done' dripping up, switch to dripping down. + this.dripping_up = false; + this.current_drip_height = 0; + } else if (this.dripping_up) { + // A non-edge drip is 'done' dripping up, move the next left drip. + this.current_drip -= 1; + this.current_drip_height = + this.crayons[this.current_drip].maxHeight; + } else { + // A non-edge drip is 'done' dripping down, move the next drip right. + this.current_drip += 1; + this.current_drip_height = 0; + //Each new drip down is assigned a random maximum height. + this.crayons[this.current_drip].maxHeight = p5.random(30, 200); + } + //Note when this drip started to calculate the height in mid-drip + this.crayons[this.current_drip].startFrame = p5.frameCount; + } + }, + getPreviewCustomizations: function () { + return getInPreviewMode() ? + {getRectHeight: () => p5.random(30, 200)} : + {getRectHeight: () => this.start_height}; + } + }; +}; diff --git a/src/effects/pineapples.js b/src/effects/pineapples.js new file mode 100644 index 00000000..caf3b797 --- /dev/null +++ b/src/effects/pineapples.js @@ -0,0 +1,50 @@ +const drawPineapple = require('../shapes/pineapple'); + +module.exports = function (p5, randomNumber, getInPreviewMode) { + return { + pineappleList: [], + init: function () { + if (this.pineappleList.length) { + return; + } + for (let i = 0; i < 8; i++) { + this.pineappleList.push({ + x: randomNumber(10, 390), + y: randomNumber(10, 390), + rot: randomNumber(0, 359), + life: 5, + }); + } + this.image = p5.createGraphics(75, 130); + this.image.scale(7); + drawPineapple(this.image.drawingContext); + }, + draw: function () { + for (let i = 0; i < this.pineappleList.length; i++) { + p5.push(); + const pineapple = this.pineappleList[i]; + const scale = this.getPreviewCustomizations().getScale(pineapple); + + p5.translate(pineapple.x, pineapple.y); + p5.rotate(pineapple.rot); + p5.scale(scale); + p5.drawingContext.drawImage(this.image.elt, -35, -65); + pineapple.life--; + if (pineapple.life < 0) { + pineapple.x = randomNumber(10, 390); + pineapple.y = randomNumber(10, 390); + pineapple.life = randomNumber(10, 120); + } + p5.pop(); + } + }, + reset: function () { + this.pineappleList = []; + }, + getPreviewCustomizations: function () { + return getInPreviewMode() ? + {getScale: () => randomNumber(10, 120) / 20 / (7 * p5.pixelDensity())} : + {getScale: pineapple => pineapple.life / 20 / (7 * p5.pixelDensity())}; + }, + }; +}; diff --git a/src/effects/pizzas.js b/src/effects/pizzas.js new file mode 100644 index 00000000..4809c8c3 --- /dev/null +++ b/src/effects/pizzas.js @@ -0,0 +1,49 @@ +const drawPizza = require('../shapes/pizza'); + +module.exports = function (p5, randomNumber, getInPreviewMode) { + return { + pizza: [], + init: function () { + if (this.pizza.length) { + return; + } + for (let i = 0; i < 10; i++) { + this.pizza.push({ + x: randomNumber(25, 375), + y: randomNumber(25, 375), + size: randomNumber(2, 6), + rot: randomNumber(0, 359), + life: 200, + }); + } + this.image = p5.createGraphics(100, 100); + this.image.scale(3); + drawPizza(this.image.drawingContext); + }, + draw: function (context) { + const centroid = this.getPreviewCustomizations().getCentroid(context); + for (let i = 0; i < this.pizza.length; i++) { + p5.push(); + const pizza = this.pizza[i]; + let scale = p5.map(centroid, 5000, 8000, 0, pizza.size); + scale = p5.constrain(scale, 0, 5); + p5.translate(pizza.x, pizza.y); + p5.rotate(pizza.rot); + p5.scale(scale / (4 * p5.pixelDensity())); + p5.drawingContext.drawImage(this.image.elt, 0, 0); + pizza.life--; + if (pizza.life < 0) { + (pizza.x = randomNumber(25, 375)), + pizza.y - randomNumber(25, 375), + (pizza.life = 200); + } + p5.pop(); + } + }, + getPreviewCustomizations: function () { + return getInPreviewMode() ? + {getCentroid: () => 6500} : + {getCentroid: context => context.centroid}; + }, + }; +}; diff --git a/src/effects/quads.js b/src/effects/quads.js new file mode 100644 index 00000000..dbc7278c --- /dev/null +++ b/src/effects/quads.js @@ -0,0 +1,60 @@ +module.exports = function (p5, colorFromPalette) { + return { + shapes: [], + init: function () { + if (!this.buffer) { + this.buffer = p5.createGraphics(400, 400); + this.buffer.noFill(); + this.buffer.stroke('#0f0'); + this.buffer.strokeWeight(2); + this.buffer.strokeJoin(p5.BEVEL); + this.buffer.background(0); + } + + for (let i = 0; i < 2; i++) { + const shape = []; + shape.color = i; + for (let j = 0; j < 4; j++) { + const vertex = p5.createSprite(); + vertex.draw = () => {}; + vertex.position = p5.createVector( + p5.random(0, 400), + p5.random(0, 400) + ); + vertex.velocity = p5.createVector(0, 2).rotate(p5.random(0, 360)); + shape.push(vertex); + } + this.shapes.push(shape); + } + this.edges = p5.createEdgeSprites(); + }, + reset: function () { + this.shapes = []; + p5.edges = null; + this.buffer.clear(); + }, + draw: function () { + this.buffer.drawingContext.globalAlpha = 0.25; + this.buffer.background(colorFromPalette(2)); + this.buffer.drawingContext.globalAlpha = 1; + + for (const shape of this.shapes) { + this.buffer.stroke(colorFromPalette(shape.color)); + this.buffer.quad.apply( + this.buffer, + shape.reduce((acc, current) => { + current.bounceOff(this.edges); + acc.push(current.position.x, current.position.y); + return acc; + }, []) + ); + } + + // Copy the off-screen buffer to the canvas. + p5.push(); + p5.scale(1 / p5.pixelDensity()); + p5.drawingContext.drawImage(this.buffer.elt, 0, 0); + p5.pop(); + }, + }; +}; diff --git a/src/effects/rain.js b/src/effects/rain.js new file mode 100644 index 00000000..4a9c688e --- /dev/null +++ b/src/effects/rain.js @@ -0,0 +1,33 @@ +module.exports = function (p5, randomNumber) { + return { + drops: [], + init: function () { + if (this.drops.length) { + return; + } + for (let i = 0; i < 20; i++) { + this.drops.push({ + x: randomNumber(0, 380), + y: randomNumber(0, 380), + length: randomNumber(10, 20), + }); + } + }, + color: p5.rgb(92, 101, 180, 0.5), + update: function () { + this.color = p5.rgb(92, 101, randomNumber(140, 220), 0.5); + }, + draw: function () { + p5.strokeWeight(3); + p5.stroke(this.color); + for (let i = 0; i < this.drops.length; i++) { + p5.push(); + p5.translate(this.drops[i].x - 20, this.drops[i].y - 20); + p5.line(0, 0, this.drops[i].length, this.drops[i].length * 2); + p5.pop(); + this.drops[i].y = (this.drops[i].y + this.drops[i].length) % 420; + this.drops[i].x = (this.drops[i].x + this.drops[i].length / 2) % 420; + } + }, + }; +}; diff --git a/src/effects/rainbow.js b/src/effects/rainbow.js new file mode 100644 index 00000000..90a791b5 --- /dev/null +++ b/src/effects/rainbow.js @@ -0,0 +1,42 @@ +module.exports = function (p5, lerpColorFromPalette) { + return { + lengths: [0, 0, 0, 0, 0, 0, 0], + current: 0, + update: function () { + this.lengths[this.lengths.length - (1 + this.current)] = 1; + this.current = (this.current + 1) % this.lengths.length; + }, + draw: function ({isPeak, bpm}) { + if (isPeak) { + this.update(); + } + p5.push(); + let backgroundColor = lerpColorFromPalette(0.5); + // Hack to set alpha for p5 + backgroundColor._array[3] = 0.25; + p5.background(backgroundColor); + p5.noFill(); + p5.strokeWeight(50); + let d, i; + for (i = 0; i < 7; i++) { + let paletteColor = lerpColorFromPalette(i * 0.14); + paletteColor._array[3] = 0.5; + p5.stroke(paletteColor); + d = 150 + i * 100; + p5.arc(0, 400, d, d, -90, 0); + if (this.lengths[i] > 0) { + // Hack to set RGB and Alpha values of p5 color objects + let [red, green, blue] = paletteColor.levels; + paletteColor.levels[0] = red - 20; + paletteColor.levels[1] = green - 20; + paletteColor.levels[2] = blue - 20; + paletteColor._array[3] = 1 - this.lengths[i] / 90; + p5.stroke(paletteColor); + p5.arc(0, 400, d, d, -90, -90 + this.lengths[i]); + this.lengths[i] = (this.lengths[i] + bpm / 50) % 90; + } + } + p5.pop(); + }, + }; +}; diff --git a/src/effects/rainingTacos.js b/src/effects/rainingTacos.js new file mode 100644 index 00000000..e19a5893 --- /dev/null +++ b/src/effects/rainingTacos.js @@ -0,0 +1,58 @@ +const drawTaco = require('../shapes/taco'); + +module.exports = function (p5, randomNumber, getInPreviewMode) { + return { + tacos: [], + init: function () { + if (this.tacos.length) { + return; + } + for (let i = 0; i < 10; i++) { + this.tacos.push({ + x: randomNumber(20, 380), + y: this.getPreviewCustomizations().y, + rot: randomNumber(0, 359), + speed: 3, + size: 5, + }); + } + this.image = p5.createGraphics(125, 50); + this.image.scale(3); + drawTaco(this.image.drawingContext); + }, + draw: function (context) { + const centroid = this.getPreviewCustomizations().getCentroid(context); + for (let i = 0; i < this.tacos.length; i++) { + p5.push(); + const taco = this.tacos[i]; + let scale = p5.map(centroid, 5000, 8000, 0, taco.size); + scale = p5.constrain(scale, 0, 5); + p5.translate(taco.x, taco.y); + p5.rotate(taco.rot); + p5.scale(scale / (4 * p5.pixelDensity())); + p5.image(this.image); + taco.y += taco.speed; + taco.rot++; + if (taco.y > 420) { + taco.x = randomNumber(20, 380); + taco.y = -50; + } + p5.pop(); + } + }, + reset: function () { + this.tacos = []; + }, + getPreviewCustomizations: function () { + return getInPreviewMode() ? + { + y: randomNumber(0, 400), + getCentroid: () => 6500, + } : + { + y: randomNumber(-400, 0), + getCentroid: context => context.centroid, + }; + }, + }; +}; diff --git a/src/effects/ripples.js b/src/effects/ripples.js new file mode 100644 index 00000000..9059d5bb --- /dev/null +++ b/src/effects/ripples.js @@ -0,0 +1,99 @@ +module.exports = function (isRandomRipple, p5, colorFromPalette, randomNumber) { + return { + // Determines whether or not the start positions of the ripples are random or centered. + isRandomRipple: isRandomRipple, + // The max width a ripple can be before it disappears. + maxRippleWidth: 575, + // The ripples which are growing. + ripples: [], + // The count of ripples which have been created since the dance started. + rippleCount: 0, + // The timestamp of when the last "draw" happened. + lastDrawTime: new Date(), + // Tracks the last biggest ripple's color so we can set that as the background after it disappears + backgroundColor: colorFromPalette(0), + + init: function () { + this.lastDrawTime = new Date(); + this.backgroundColor = colorFromPalette(0); + this.ripples = []; + // If the starting location is random, then the circles might need to be 2x as wide to fill the screen. + if (isRandomRipple) { + this.maxRippleWidth = 1150; + } + // put some initial ripples. + for (let i = 0; i < 6; i++) { + this.ripples.push( + this.createRipple( + this.maxRippleWidth * (0.85 - 0.15 * i), + this.isRandomRipple + ) + ); + } + }, + + draw: function ({isPeak, bpm}) { + let currentTime = new Date(); + let maxRippleWidth = this.maxRippleWidth; + p5.background(this.backgroundColor); + // On each "peak", create a new ripple. + if (isPeak) { + this.ripples.push(this.createRipple(1, this.isRandomRipple)); + } + p5.push(); + p5.noStroke(); + p5.ellipseMode(p5.CENTER); + // calculate how much the ripples have grown and draw them. + let rippleWidthGrowth = this.getRippleGrowth(currentTime, bpm); + for (let i = 0; i < this.ripples.length; i++) { + let ripple = this.ripples[i]; + ripple.width += rippleWidthGrowth; + p5.fill(ripple.color); + p5.ellipse(ripple.x, ripple.y, ripple.width); + } + // remove ripples which are too big, and updated the backgroundColor to match the highest one. + let backgroundColor = this.backgroundColor; + this.ripples = this.ripples.filter(function (ripple) { + if (ripple.width < maxRippleWidth) { + return true; + } else { + backgroundColor = ripple.color; + return false; + } + }); + this.backgroundColor = backgroundColor; + p5.pop(); + // keep track of the draw times so we can calculate how much time has passed. + this.lastDrawTime = currentTime; + }, + + // creates a object representing the size and position of a ripple given an initial width + createRipple: function (width, isRandom) { + let x = 200; + let y = 200; + if (isRandom) { + x = randomNumber(20, 380); + y = randomNumber(20, 380); + } + return { + x: x, + y: y, + color: colorFromPalette(++this.rippleCount), + width: width, + }; + }, + + // calculates the increase in width a ripple will experience depending on the + // amount of time which has passed since the last drawm and the current BPM. + getRippleGrowth: function (currentTime, bpm) { + if (bpm === 0) { + return 0; + } + // Velocity of the ripple width expansion. + let velocity = this.maxRippleWidth / (bpm / 60) / 1.5; + // Calculate how much time has passed so we know how wide the ripple should be. + let deltaTime = (currentTime - this.lastDrawTime) / 1000; + return Math.floor(velocity * deltaTime); + }, + }; +}; diff --git a/src/effects/smileFace.js b/src/effects/smileFace.js new file mode 100644 index 00000000..f1d13c83 --- /dev/null +++ b/src/effects/smileFace.js @@ -0,0 +1,50 @@ +const drawSmiley = require('../shapes/smiley'); + +module.exports = function (p5, randomNumber, getInPreviewMode) { + return { + smiles: [], + init: function () { + if (this.smiles.length) { + return; + } + for (let i = 0; i < 10; i++) { + this.smiles.push({ + x: randomNumber(25, 375), + y: randomNumber(25, 375), + size: randomNumber(2, 6), + rot: randomNumber(0, 359), + life: 200, + }); + } + this.image = p5.createGraphics(100, 100); + this.image.scale(3); + drawSmiley(this.image.drawingContext, 0.8); + }, + draw: function (context) { + const centroid = this.getPreviewCustomizations().getCentroid(context); + + for (let i = 0; i < this.smiles.length; i++) { + p5.push(); + const smiles = this.smiles[i]; + let scale = p5.map(centroid, 5000, 8000, 0, smiles.size); + scale = p5.constrain(scale, 0, 5); + p5.translate(smiles.x, smiles.y); + p5.rotate(smiles.rot); + p5.scale(scale / (4 * p5.pixelDensity())); + p5.drawingContext.drawImage(this.image.elt, 0, 0); + smiles.life--; + if (smiles.life < 0) { + (smiles.x = randomNumber(25, 375)), + smiles.y - randomNumber(25, 375), + (smiles.life = 200); + } + p5.pop(); + } + }, + getPreviewCustomizations: function () { + return getInPreviewMode() ? + {getCentroid: () => 6500} : + {getCentroid: context => context.centroid}; + }, + }; +}; diff --git a/src/effects/smilingPoop.js b/src/effects/smilingPoop.js new file mode 100644 index 00000000..6adb77f8 --- /dev/null +++ b/src/effects/smilingPoop.js @@ -0,0 +1,46 @@ +const drawPoop = require('../shapes/poop'); + +module.exports = function (p5, randomNumber, getInPreviewMode) { + return { + poopList: [], + init: function () { + if (this.poopList.length) { + return; + } + for (let i = 0; i < 6; i++) { + this.poopList.push({ + x: randomNumber(10, 390), + y: randomNumber(10, 390), + rot: randomNumber(0, 359), + life: 5, + }); + } + }, + draw: function () { + for (const poop of this.poopList) { + const scale = this.getPreviewCustomizations().getScale(poop); + + p5.push(); + p5.translate(poop.x, poop.y); + p5.rotate(poop.rot); + p5.scale(scale); + drawPoop(p5._renderer.drawingContext); + poop.life--; + if (poop.life < 0) { + poop.x = randomNumber(10, 390); + poop.y = randomNumber(10, 390); + poop.life = randomNumber(10, 120); + } + p5.pop(); + } + }, + reset: function () { + this.poopList = []; + }, + getPreviewCustomizations: function () { + return getInPreviewMode() ? + {getScale: () => randomNumber(10, 120) / 20} : + {getScale: poop => poop.life / 20}; + }, + }; +}; diff --git a/src/effects/snowflakes.js b/src/effects/snowflakes.js new file mode 100644 index 00000000..c4927a9d --- /dev/null +++ b/src/effects/snowflakes.js @@ -0,0 +1,43 @@ +module.exports = function (p5, lerpColorFromPalette, getInPreviewMode) { + return { + flake: [], + draw: function () { + p5.background(lerpColorFromPalette(0.5)); + const numSnowflakesToDraw = this.getPreviewCustomizations().numSnowflakesToDraw; + for (let i = 0; i < numSnowflakesToDraw; i++) { + let flake = { + x: p5.random(-100, 400), + y: this.getPreviewCustomizations().y, + velocityX: p5.random(-2, 2), + size: p5.random(6, 12), + }; + this.flake.push(flake); + } + p5.noStroke(); + p5.fill('white'); + this.flake.forEach(function (flake) { + p5.push(); + p5.translate(flake.x, flake.y); + for (let i = 0; i < 5; i++) { + p5.rotate(360 / 5); + p5.ellipse(0, 0, 1, flake.size); + } + let fallSpeed = p5.map(flake.size, 6, 12, 2, 5); + flake.y += fallSpeed; + flake.x += flake.velocityX; + p5.pop(); + }); + this.flake = this.flake.filter(function (flake) { + return flake.y < 425; + }); + }, + reset: function () { + this.flake = []; + }, + getPreviewCustomizations: function () { + return getInPreviewMode() ? + {numSnowflakesToDraw: 200, y: p5.random(-100, 400)} : + {numSnowflakesToDraw: 1, y: -10}; + }, + }; +}; diff --git a/src/effects/sparkles.js b/src/effects/sparkles.js new file mode 100644 index 00000000..385c8060 --- /dev/null +++ b/src/effects/sparkles.js @@ -0,0 +1,43 @@ +const drawSparkle = require('../shapes/sparkle'); + +module.exports = function (p5, randomColorFromPalette, randomNumber) { + return { + sparkles: [], + maxSparkles: 80, + makeRandomSparkle: function () { + return { + x: randomNumber(-100, 600), + y: randomNumber(0, 400), + color: randomColorFromPalette(), + }; + }, + init: function () { + if (this.sparkles.length) { + return; + } + for (let i = 0; i < this.maxSparkles; i++) { + this.sparkles.push(this.makeRandomSparkle()); + } + }, + update: function () {}, + draw: function ({bpm}) { + // Provide a default value for bpm of song when not provided so that + // sparkles effect is drawn even in preview mode. + bpm = bpm || 120; + p5.background('#2b1e45'); + let velocity = Math.floor((bpm / 90) * 3); + for (let i = 0; i < this.maxSparkles; i++) { + p5.push(); + if (this.sparkles[i].x < 10 || this.sparkles[i].y > 410) { + this.sparkles[i] = this.makeRandomSparkle(); + } + + this.sparkles[i].x -= velocity; + this.sparkles[i].y += velocity; + p5.translate(this.sparkles[i].x, this.sparkles[i].y); + drawSparkle(p5._renderer.drawingContext, this.sparkles[i].color); + p5.pop(); + } + }, + }; +}; diff --git a/src/effects/spiral.js b/src/effects/spiral.js new file mode 100644 index 00000000..0a3a82ca --- /dev/null +++ b/src/effects/spiral.js @@ -0,0 +1,31 @@ +const drawSpiral = require('../shapes/spiral'); + +module.exports = function (p5, lerpColorFromPalette) { + return { + angle: 0, + color: 0, + init: function () { + this.color = 0; + }, + update: function () { + this.color += 0.13; + if (this.color > 1) { + this.color -= 1; + } + }, + draw: function ({isPeak, bpm}) { + if (isPeak) { + this.update(); + } + p5.background(lerpColorFromPalette(this.color)); + p5.push(); + p5.translate(200, 200); + let rotation = (bpm / 90) * 200; + this.angle -= rotation; + p5.rotate((Math.PI / 180) * this.angle); + p5.translate(-600, -600); + drawSpiral(p5._renderer.drawingContext); + p5.pop(); + }, + }; +}; diff --git a/src/effects/splatter.js b/src/effects/splatter.js new file mode 100644 index 00000000..1af68d2a --- /dev/null +++ b/src/effects/splatter.js @@ -0,0 +1,57 @@ +module.exports = function (p5, randomColorFromPalette) { + return { + buffer: null, + splats: [], + numSplats: 5, + randomSplat: function () { + return { + x: p5.random(0, 400), + y: p5.random(0, 400), + r: p5.random(5, 15), + color: randomColorFromPalette(), + }; + }, + init: function () { + this.splats.length = 0; + for (let i = 0; i < this.numSplats; i++) { + this.splats.push(this.randomSplat()); + } + + if (this.buffer) { + this.buffer.clear(); + return; + } + this.buffer = p5.createGraphics(p5.width, p5.height); + this.buffer.noStroke(); + this.buffer.drawingContext.globalAlpha = 0.8; + }, + draw: function () { + // first make a pass and remove items, traversing in reverse so that removals + // dont affect traversal + for (let splat of this.splats) { + if (splat.r > 30) { + splat.x = p5.random(0, 400); + splat.y = p5.random(0, 400); + splat.r = p5.random(5, 15); + splat.color = randomColorFromPalette(); + } + + splat.r += p5.random(1); + this.buffer.fill(splat.color); + for (let i = 0; i < 20; i++) { + this.buffer.ellipse( + p5.randomGaussian(splat.x, splat.r), + p5.randomGaussian(splat.y, splat.r), + p5.random(2, 8) + ); + } + } + + // Copy the off-screen buffer to the canvas. + p5.push(); + p5.scale(1 / p5.pixelDensity()); + p5.drawingContext.drawImage(this.buffer.elt, 0, 0); + p5.pop(); + }, + }; +}; diff --git a/src/effects/spotlight.js b/src/effects/spotlight.js new file mode 100644 index 00000000..82414b09 --- /dev/null +++ b/src/effects/spotlight.js @@ -0,0 +1,50 @@ +module.exports = function (p5, randomNumber) { + return { + x: 200, + y: 200, + targetX: null, + targetY: null, + dx: 0, + dy: 0, + diameter: 0, + swirl: null, + init: function () { + this.targetX = 200; + this.targetY = 200; + this.update(); + }, + update: function () { + while ( + Math.sqrt( + (this.targetY - this.y) ** 2 + (this.targetX - this.x) ** 2 + ) < 40 + ) { + this.targetX = randomNumber(50, 350); + this.targetY = randomNumber(50, 350); + } + let angleOfMovement = Math.atan2( + this.targetY - this.y, + this.targetX - this.x + ); + this.dx = 6 * Math.cos(angleOfMovement); + this.dy = 6 * Math.sin(angleOfMovement); + }, + draw: function ({isPeak}) { + if ( + isPeak || + (Math.abs(this.targetX - this.x) < 4 && + Math.abs(this.targetY - this.y) < 4) + ) { + this.update(); + } + p5.push(); + p5.noFill(); + p5.stroke('#000'); + p5.strokeWeight(600); + this.x += this.dx + randomNumber(-1, 1); + this.y += this.dy + randomNumber(-1, 1); + p5.ellipse(this.x, this.y, 800, 800); + p5.pop(); + }, + }; +}; diff --git a/src/effects/squiggles.js b/src/effects/squiggles.js new file mode 100644 index 00000000..ab80ab56 --- /dev/null +++ b/src/effects/squiggles.js @@ -0,0 +1,37 @@ +module.exports = function (p5, lerpColorFromPalette) { + return { + points: [], + dotSpacing: 4, + amplitude: 40, + period: 400, + dotRadius: 14, + numSquiggles: 5, + init: function () { + this.points = []; + p5.noStroke(); + p5.angleMode(p5.DEGREES); + let numPoints = p5.height / this.dotSpacing; + for (var i = 0; i < numPoints; i++) { + this.points.push({ + x: 0, + y: i * this.dotSpacing, + theta: (360 / this.period) * i * this.dotSpacing, + color: lerpColorFromPalette(i / numPoints), + }); + } + }, + draw: function ({bpm}) { + p5.background('black'); + for (var i = 0; i < this.numSquiggles; i++) { + this.points.forEach(point => { + p5.fill(point.color); + p5.ellipse(point.x, point.y, this.dotRadius, this.dotRadius); + point.x = + (p5.width / (this.numSquiggles - 1)) * i + + p5.sin(point.theta) * this.amplitude; + point.theta = (point.theta + bpm / 360) % 360; + }); + } + }, + }; +}; diff --git a/src/effects/starburst.js b/src/effects/starburst.js new file mode 100644 index 00000000..9a5ff612 --- /dev/null +++ b/src/effects/starburst.js @@ -0,0 +1,26 @@ +const drawStarburst = require('../shapes/starburst'); +const drawStar = require('../shapes/star'); + +// This background effect is inspired by the Poetry foreground effect 'starburst' +// https://github.com/code-dot-org/code-dot-org/blob/381e9b93f7cbd081738dfa7adbc9e7ce4e169a0c/apps/src/p5lab/poetry/commands/foregroundEffects.js#L235 +module.exports = function (p5, lerpColorFromPalette, randomColorFromPalette, randomNumber) { + return { + stars: [], + init: function () { + this.stars = []; + p5.push(); + p5.background(lerpColorFromPalette(0)); + // A call to drawStarburst with isPreview=true will ensure background effect + // is displayed in preview. + drawStarburst(p5, true, this.stars, randomNumber, randomColorFromPalette, drawStar); + p5.pop(); + }, + draw: function () { + p5.push(); + p5.noStroke(); + p5.background(lerpColorFromPalette(0)); + drawStarburst(p5, false, this.stars, randomNumber, randomColorFromPalette, drawStar); + p5.pop(); + }, + }; +}; diff --git a/src/effects/stars.js b/src/effects/stars.js new file mode 100644 index 00000000..ac5c7122 --- /dev/null +++ b/src/effects/stars.js @@ -0,0 +1,44 @@ +module.exports = function (p5, randomColorFromPalette, getInPreviewMode) { + return { + star: [], + draw: function () { + p5.background('#303030'); + const numStarsToDraw = this.getPreviewCustomizations().numStarsToDraw; + for (let i = 0; i < numStarsToDraw; i++) { + let star = { + x: p5.random(0, 400), + y: p5.random(0, 400), + size: p5.random(15, 30), + color: randomColorFromPalette(), + }; + this.star.push(star); + } + + p5.noStroke(); + this.star.forEach(function (star) { + p5.push(); + p5.fill(star.color); + p5.translate(star.x, star.y); + for (let i = 0; i < 3; i++) { + p5.rotate(360 / 5); + p5.ellipse(0, 0, 1, star.size); + } + let fadeSpeed = p5.map(star.size, 15, 30, 1, 2); + star.size = star.size - fadeSpeed; + star.y = star.y - 2; + p5.pop(); + }); + this.star = this.star.filter(function (star) { + return star.size > 0.1; + }); + }, + reset: function () { + this.star = []; + }, + getPreviewCustomizations: function () { + return getInPreviewMode() ? + {numStarsToDraw: 30} : + {numStarsToDraw: 1}; + } + }; +}; diff --git a/src/effects/swirl.js b/src/effects/swirl.js new file mode 100644 index 00000000..26bbae84 --- /dev/null +++ b/src/effects/swirl.js @@ -0,0 +1,25 @@ +const drawSwirl = require('../shapes/swirl'); + +module.exports = function (p5, randomColorFromPalette) { + return { + angle: 0, + color: null, + update: function () { + this.color = randomColorFromPalette(); + }, + draw: function ({isPeak, bpm}) { + if (isPeak || !this.color) { + this.update(); + } + p5.push(); + p5.background(this.color); + p5.translate(200, 200); + let rotation = (bpm / 90) * 50; + this.angle -= rotation; + p5.rotate((Math.PI / 180) * this.angle); + p5.translate(-427, -400); + drawSwirl(p5._renderer.drawingContext); + p5.pop(); + }, + }; +}; diff --git a/src/effects/text.js b/src/effects/text.js new file mode 100644 index 00000000..9c11104e --- /dev/null +++ b/src/effects/text.js @@ -0,0 +1,40 @@ +module.exports = function (p5, lerpColorFromPalette, colorFromHue, randomNumber) { + return { + texts: [], + maxTexts: 10, + update: function (text, hue, size) { + this.texts.push({ + x: randomNumber(25, 375), + y: randomNumber(25, 375), + text: text, + font: 'Arial', + color: lerpColorFromPalette(hue / 360), + size: size, + }); + if (this.texts.length > this.maxTexts) { + this.texts.shift(); + } + }, + draw: function ({isPeak, centroid, artist, title}) { + if (isPeak) { + let text; + if (randomNumber(0, 1) === 0) { + text = artist; + } else { + text = title; + } + this.update(text, centroid, randomNumber(14, 48)); + } + p5.push(); + p5.background(colorFromHue(0, 0, 40)); + p5.textAlign(p5.CENTER, p5.CENTER); + this.texts.forEach(function (t) { + p5.textSize(t.size); + p5.textFont(t.font); + p5.fill(t.color); + p5.text(t.text, t.x, t.y); + }); + p5.pop(); + }, + }; +}; From 597b7fc4a9cc1a0b33b7d23de319391fd4779f53 Mon Sep 17 00:00:00 2001 From: Ben Brooks Date: Thu, 30 Nov 2023 16:47:50 -0800 Subject: [PATCH 2/3] Move into foreground and background folders --- src/Effects.js | 91 ++++++++++--------- .../{ => background}/bloomingPetals.js | 6 +- src/effects/{ => background}/circles.js | 0 src/effects/{ => background}/clouds.js | 2 +- src/effects/{ => background}/colorCycle.js | 0 src/effects/{ => background}/diamonds.js | 0 src/effects/{ => background}/disco.js | 0 src/effects/{ => background}/discoBall.js | 2 +- src/effects/{ => background}/fireworks.js | 2 +- src/effects/{ => background}/flowers.js | 0 src/effects/{ => background}/frostedGrid.js | 6 +- src/effects/{ => background}/galaxy.js | 0 src/effects/{ => background}/growingStars.js | 2 +- src/effects/{ => background}/higherPower.js | 2 +- src/effects/{ => background}/kaleidoscope.js | 0 src/effects/{ => background}/lasers.js | 0 src/effects/{ => background}/musicWave.js | 0 src/effects/{ => background}/quads.js | 0 src/effects/{ => background}/rainbow.js | 0 src/effects/{ => background}/ripples.js | 0 src/effects/{ => background}/snowflakes.js | 0 src/effects/{ => background}/sparkles.js | 2 +- src/effects/{ => background}/spiral.js | 2 +- src/effects/{ => background}/splatter.js | 0 src/effects/{ => background}/squiggles.js | 0 src/effects/{ => background}/starburst.js | 4 +- src/effects/{ => background}/stars.js | 0 src/effects/{ => background}/swirl.js | 2 +- src/effects/{ => background}/text.js | 0 src/effects/{ => foreground}/bubbles.js | 0 src/effects/{ => foreground}/colorLights.js | 0 src/effects/{ => foreground}/confetti.js | 0 src/effects/{ => foreground}/emojis.js | 10 +- .../{ => foreground}/explodingStars.js | 2 +- .../{ => foreground}/floatingRainbows.js | 2 +- .../{ => foreground}/heartsColorful.js | 2 +- src/effects/{ => foreground}/heartsRed.js | 2 +- src/effects/{ => foreground}/musicNotes.js | 2 +- src/effects/{ => foreground}/paintDrip.js | 0 src/effects/{ => foreground}/pineapples.js | 2 +- src/effects/{ => foreground}/pizzas.js | 2 +- src/effects/{ => foreground}/rain.js | 0 src/effects/{ => foreground}/rainingTacos.js | 2 +- src/effects/{ => foreground}/smileFace.js | 2 +- src/effects/{ => foreground}/smilingPoop.js | 2 +- src/effects/{ => foreground}/spotlight.js | 0 46 files changed, 77 insertions(+), 76 deletions(-) rename src/effects/{ => background}/bloomingPetals.js (93%) rename src/effects/{ => background}/circles.js (100%) rename src/effects/{ => background}/clouds.js (96%) rename src/effects/{ => background}/colorCycle.js (100%) rename src/effects/{ => background}/diamonds.js (100%) rename src/effects/{ => background}/disco.js (100%) rename src/effects/{ => background}/discoBall.js (98%) rename src/effects/{ => background}/fireworks.js (98%) rename src/effects/{ => background}/flowers.js (100%) rename src/effects/{ => background}/frostedGrid.js (88%) rename src/effects/{ => background}/galaxy.js (100%) rename src/effects/{ => background}/growingStars.js (94%) rename src/effects/{ => background}/higherPower.js (97%) rename src/effects/{ => background}/kaleidoscope.js (100%) rename src/effects/{ => background}/lasers.js (100%) rename src/effects/{ => background}/musicWave.js (100%) rename src/effects/{ => background}/quads.js (100%) rename src/effects/{ => background}/rainbow.js (100%) rename src/effects/{ => background}/ripples.js (100%) rename src/effects/{ => background}/snowflakes.js (100%) rename src/effects/{ => background}/sparkles.js (95%) rename src/effects/{ => background}/spiral.js (93%) rename src/effects/{ => background}/splatter.js (100%) rename src/effects/{ => background}/squiggles.js (100%) rename src/effects/{ => background}/starburst.js (89%) rename src/effects/{ => background}/stars.js (100%) rename src/effects/{ => background}/swirl.js (92%) rename src/effects/{ => background}/text.js (100%) rename src/effects/{ => foreground}/bubbles.js (100%) rename src/effects/{ => foreground}/colorLights.js (100%) rename src/effects/{ => foreground}/confetti.js (100%) rename src/effects/{ => foreground}/emojis.js (91%) rename src/effects/{ => foreground}/explodingStars.js (96%) rename src/effects/{ => foreground}/floatingRainbows.js (96%) rename src/effects/{ => foreground}/heartsColorful.js (95%) rename src/effects/{ => foreground}/heartsRed.js (95%) rename src/effects/{ => foreground}/musicNotes.js (96%) rename src/effects/{ => foreground}/paintDrip.js (100%) rename src/effects/{ => foreground}/pineapples.js (96%) rename src/effects/{ => foreground}/pizzas.js (96%) rename src/effects/{ => foreground}/rain.js (100%) rename src/effects/{ => foreground}/rainingTacos.js (97%) rename src/effects/{ => foreground}/smileFace.js (96%) rename src/effects/{ => foreground}/smilingPoop.js (96%) rename src/effects/{ => foreground}/spotlight.js (100%) diff --git a/src/Effects.js b/src/Effects.js index 888b07e6..68e4ac9a 100644 --- a/src/Effects.js +++ b/src/Effects.js @@ -1,52 +1,53 @@ const constants = require('./constants'); -const discoBall = require('./effects/discoBall'); -const higherPower = require('./effects/higherPower'); -const rainbow = require('./effects/rainbow'); -const flowers = require('./effects/flowers'); -const colorCycle = require('./effects/colorCycle'); -const disco = require('./effects/disco'); -const ripples = require('./effects/ripples'); -const bloomingPetals = require('./effects/bloomingPetals'); -const clouds = require('./effects/clouds'); -const frostedGrid = require('./effects/frostedGrid'); -const starburst = require('./effects/starburst'); -const diamonds = require('./effects/diamonds'); -const circles = require('./effects/circles'); -const sparkles = require('./effects/sparkles'); -const text = require('./effects/text'); -const splatter = require('./effects/splatter'); -const swirl = require('./effects/swirl'); -const spiral = require('./effects/spiral'); -const lasers = require('./effects/lasers'); -const quads = require('./effects/quads'); -const kaleidoscope = require('./effects/kaleidoscope'); -const snowflakes = require('./effects/snowflakes'); -const fireworks = require('./effects/fireworks'); -const stars = require('./effects/stars'); -const galaxy = require('./effects/galaxy'); -const growingStars = require('./effects/growingStars'); -const squiggles = require('./effects/squiggles'); -const musicWave = require('./effects/musicWave'); +// background +const discoBall = require('./effects/background/discoBall'); +const higherPower = require('./effects/background/higherPower'); +const rainbow = require('./effects/background/rainbow'); +const flowers = require('./effects/background/flowers'); +const colorCycle = require('./effects/background/colorCycle'); +const disco = require('./effects/background/disco'); +const ripples = require('./effects/background/ripples'); +const bloomingPetals = require('./effects/background/bloomingPetals'); +const clouds = require('./effects/background/clouds'); +const frostedGrid = require('./effects/background/frostedGrid'); +const starburst = require('./effects/background/starburst'); +const diamonds = require('./effects/background/diamonds'); +const circles = require('./effects/background/circles'); +const sparkles = require('./effects/background/sparkles'); +const text = require('./effects/background/text'); +const splatter = require('./effects/background/splatter'); +const swirl = require('./effects/background/swirl'); +const spiral = require('./effects/background/spiral'); +const lasers = require('./effects/background/lasers'); +const quads = require('./effects/background/quads'); +const kaleidoscope = require('./effects/background/kaleidoscope'); +const snowflakes = require('./effects/background/snowflakes'); +const fireworks = require('./effects/background/fireworks'); +const stars = require('./effects/background/stars'); +const galaxy = require('./effects/background/galaxy'); +const growingStars = require('./effects/background/growingStars'); +const squiggles = require('./effects/background/squiggles'); +const musicWave = require('./effects/background/musicWave'); // foreground -const rain = require('./effects/rain'); -const rainingTacos = require('./effects/rainingTacos'); -const pineapples = require('./effects/pineapples'); -const spotlight = require('./effects/spotlight'); -const colorLights = require('./effects/colorLights'); -const smilingPoop = require('./effects/smilingPoop'); -const heartsRed = require('./effects/heartsRed'); -const heartsColorful = require('./effects/heartsColorful'); -const floatingRainbows = require('./effects/floatingRainbows'); -const bubbles = require('./effects/bubbles'); -const explodingStars = require('./effects/explodingStars'); -const pizzas = require('./effects/pizzas'); -const smileFace = require('./effects/smileFace'); -const confetti = require('./effects/confetti'); -const musicNotes = require('./effects/musicNotes'); -const paintDrip = require('./effects/paintDrip'); -const emojis = require('./effects/emojis'); +const rain = require('./effects/foreground/rain'); +const rainingTacos = require('./effects/foreground/rainingTacos'); +const pineapples = require('./effects/foreground/pineapples'); +const spotlight = require('./effects/foreground/spotlight'); +const colorLights = require('./effects/foreground/colorLights'); +const smilingPoop = require('./effects/foreground/smilingPoop'); +const heartsRed = require('./effects/foreground/heartsRed'); +const heartsColorful = require('./effects/foreground/heartsColorful'); +const floatingRainbows = require('./effects/foreground/floatingRainbows'); +const bubbles = require('./effects/foreground/bubbles'); +const explodingStars = require('./effects/foreground/explodingStars'); +const pizzas = require('./effects/foreground/pizzas'); +const smileFace = require('./effects/foreground/smileFace'); +const confetti = require('./effects/foreground/confetti'); +const musicNotes = require('./effects/foreground/musicNotes'); +const paintDrip = require('./effects/foreground/paintDrip'); +const emojis = require('./effects/foreground/emojis'); module.exports = class Effects { constructor(p5, alpha, extraImages, blend, currentPalette = 'default') { diff --git a/src/effects/bloomingPetals.js b/src/effects/background/bloomingPetals.js similarity index 93% rename from src/effects/bloomingPetals.js rename to src/effects/background/bloomingPetals.js index 1e993dff..722c88ea 100644 --- a/src/effects/bloomingPetals.js +++ b/src/effects/background/bloomingPetals.js @@ -1,6 +1,6 @@ -const constants = require('../constants'); -const {hexToRgb} = require('../utils'); -const drawPetal = require('../shapes/petal'); +const constants = require('../../constants'); +const {hexToRgb} = require('../../utils'); +const drawPetal = require('../../shapes/petal'); // This effect is slightly modified from Poetry background effect 'blooming' // https://github.com/code-dot-org/code-dot-org/blob/381e9b93f7cbd081738dfa7adbc9e7ce4e169a0c/apps/src/p5lab/poetry/commands/backgroundEffects.js#L245 diff --git a/src/effects/circles.js b/src/effects/background/circles.js similarity index 100% rename from src/effects/circles.js rename to src/effects/background/circles.js diff --git a/src/effects/clouds.js b/src/effects/background/clouds.js similarity index 96% rename from src/effects/clouds.js rename to src/effects/background/clouds.js index 0adee876..61902cf4 100644 --- a/src/effects/clouds.js +++ b/src/effects/background/clouds.js @@ -1,4 +1,4 @@ -const {getP5Color} = require('../utils'); +const {getP5Color} = require('../../utils'); // This effect is slightly modified from Poetry background effect 'clouds' // https://github.com/code-dot-org/code-dot-org/blob/381e9b93f7cbd081738dfa7adbc9e7ce4e169a0c/apps/src/p5lab/poetry/commands/backgroundEffects.js#L368 diff --git a/src/effects/colorCycle.js b/src/effects/background/colorCycle.js similarity index 100% rename from src/effects/colorCycle.js rename to src/effects/background/colorCycle.js diff --git a/src/effects/diamonds.js b/src/effects/background/diamonds.js similarity index 100% rename from src/effects/diamonds.js rename to src/effects/background/diamonds.js diff --git a/src/effects/disco.js b/src/effects/background/disco.js similarity index 100% rename from src/effects/disco.js rename to src/effects/background/disco.js diff --git a/src/effects/discoBall.js b/src/effects/background/discoBall.js similarity index 98% rename from src/effects/discoBall.js rename to src/effects/background/discoBall.js index 83c33494..45228b4c 100644 --- a/src/effects/discoBall.js +++ b/src/effects/background/discoBall.js @@ -1,4 +1,4 @@ -const drawSparkle = require("../shapes/sparkle"); +const drawSparkle = require("../../shapes/sparkle"); module.exports = function (p5, lerpColorFromPalette, colorFromPalette) { return { diff --git a/src/effects/fireworks.js b/src/effects/background/fireworks.js similarity index 98% rename from src/effects/fireworks.js rename to src/effects/background/fireworks.js index f9e27b32..f3e887ff 100644 --- a/src/effects/fireworks.js +++ b/src/effects/background/fireworks.js @@ -1,4 +1,4 @@ -const drawSparkle = require('../shapes/sparkle'); +const drawSparkle = require('../../shapes/sparkle'); module.exports = function (p5, randomColorFromPalette, randomNumber) { return { diff --git a/src/effects/flowers.js b/src/effects/background/flowers.js similarity index 100% rename from src/effects/flowers.js rename to src/effects/background/flowers.js diff --git a/src/effects/frostedGrid.js b/src/effects/background/frostedGrid.js similarity index 88% rename from src/effects/frostedGrid.js rename to src/effects/background/frostedGrid.js index e48a05d8..e9d5f88f 100644 --- a/src/effects/frostedGrid.js +++ b/src/effects/background/frostedGrid.js @@ -1,6 +1,6 @@ -const constants = require('../constants'); -const {hexToRgb} = require('../utils'); -const drawFrostedGrid = require('../shapes/frostedGrid'); +const constants = require('../../constants'); +const {hexToRgb} = require('../../utils'); +const drawFrostedGrid = require('../../shapes/frostedGrid'); // This effect is slightly modified from Poetry background effect 'fadeColors' // https://github.com/code-dot-org/code-dot-org/blob/381e9b93f7cbd081738dfa7adbc9e7ce4e169a0c/apps/src/p5lab/poetry/commands/backgroundEffects.js#L181 diff --git a/src/effects/galaxy.js b/src/effects/background/galaxy.js similarity index 100% rename from src/effects/galaxy.js rename to src/effects/background/galaxy.js diff --git a/src/effects/growingStars.js b/src/effects/background/growingStars.js similarity index 94% rename from src/effects/growingStars.js rename to src/effects/background/growingStars.js index c10882ac..ccb5ce69 100644 --- a/src/effects/growingStars.js +++ b/src/effects/background/growingStars.js @@ -1,4 +1,4 @@ -const drawStar = require('../shapes/star'); +const drawStar = require('../../shapes/star'); module.exports = function (p5, colorFromPalette) { return { diff --git a/src/effects/higherPower.js b/src/effects/background/higherPower.js similarity index 97% rename from src/effects/higherPower.js rename to src/effects/background/higherPower.js index a2628a95..37581a5c 100644 --- a/src/effects/higherPower.js +++ b/src/effects/background/higherPower.js @@ -1,4 +1,4 @@ -const constants = require("../constants"); +const constants = require("../../constants"); module.exports = function (p5, getCurrentPalette, extraImages) { return { diff --git a/src/effects/kaleidoscope.js b/src/effects/background/kaleidoscope.js similarity index 100% rename from src/effects/kaleidoscope.js rename to src/effects/background/kaleidoscope.js diff --git a/src/effects/lasers.js b/src/effects/background/lasers.js similarity index 100% rename from src/effects/lasers.js rename to src/effects/background/lasers.js diff --git a/src/effects/musicWave.js b/src/effects/background/musicWave.js similarity index 100% rename from src/effects/musicWave.js rename to src/effects/background/musicWave.js diff --git a/src/effects/quads.js b/src/effects/background/quads.js similarity index 100% rename from src/effects/quads.js rename to src/effects/background/quads.js diff --git a/src/effects/rainbow.js b/src/effects/background/rainbow.js similarity index 100% rename from src/effects/rainbow.js rename to src/effects/background/rainbow.js diff --git a/src/effects/ripples.js b/src/effects/background/ripples.js similarity index 100% rename from src/effects/ripples.js rename to src/effects/background/ripples.js diff --git a/src/effects/snowflakes.js b/src/effects/background/snowflakes.js similarity index 100% rename from src/effects/snowflakes.js rename to src/effects/background/snowflakes.js diff --git a/src/effects/sparkles.js b/src/effects/background/sparkles.js similarity index 95% rename from src/effects/sparkles.js rename to src/effects/background/sparkles.js index 385c8060..dca5d174 100644 --- a/src/effects/sparkles.js +++ b/src/effects/background/sparkles.js @@ -1,4 +1,4 @@ -const drawSparkle = require('../shapes/sparkle'); +const drawSparkle = require('../../shapes/sparkle'); module.exports = function (p5, randomColorFromPalette, randomNumber) { return { diff --git a/src/effects/spiral.js b/src/effects/background/spiral.js similarity index 93% rename from src/effects/spiral.js rename to src/effects/background/spiral.js index 0a3a82ca..776ade27 100644 --- a/src/effects/spiral.js +++ b/src/effects/background/spiral.js @@ -1,4 +1,4 @@ -const drawSpiral = require('../shapes/spiral'); +const drawSpiral = require('../../shapes/spiral'); module.exports = function (p5, lerpColorFromPalette) { return { diff --git a/src/effects/splatter.js b/src/effects/background/splatter.js similarity index 100% rename from src/effects/splatter.js rename to src/effects/background/splatter.js diff --git a/src/effects/squiggles.js b/src/effects/background/squiggles.js similarity index 100% rename from src/effects/squiggles.js rename to src/effects/background/squiggles.js diff --git a/src/effects/starburst.js b/src/effects/background/starburst.js similarity index 89% rename from src/effects/starburst.js rename to src/effects/background/starburst.js index 9a5ff612..940d0c66 100644 --- a/src/effects/starburst.js +++ b/src/effects/background/starburst.js @@ -1,5 +1,5 @@ -const drawStarburst = require('../shapes/starburst'); -const drawStar = require('../shapes/star'); +const drawStarburst = require('../../shapes/starburst'); +const drawStar = require('../../shapes/star'); // This background effect is inspired by the Poetry foreground effect 'starburst' // https://github.com/code-dot-org/code-dot-org/blob/381e9b93f7cbd081738dfa7adbc9e7ce4e169a0c/apps/src/p5lab/poetry/commands/foregroundEffects.js#L235 diff --git a/src/effects/stars.js b/src/effects/background/stars.js similarity index 100% rename from src/effects/stars.js rename to src/effects/background/stars.js diff --git a/src/effects/swirl.js b/src/effects/background/swirl.js similarity index 92% rename from src/effects/swirl.js rename to src/effects/background/swirl.js index 26bbae84..957d9a9a 100644 --- a/src/effects/swirl.js +++ b/src/effects/background/swirl.js @@ -1,4 +1,4 @@ -const drawSwirl = require('../shapes/swirl'); +const drawSwirl = require('../../shapes/swirl'); module.exports = function (p5, randomColorFromPalette) { return { diff --git a/src/effects/text.js b/src/effects/background/text.js similarity index 100% rename from src/effects/text.js rename to src/effects/background/text.js diff --git a/src/effects/bubbles.js b/src/effects/foreground/bubbles.js similarity index 100% rename from src/effects/bubbles.js rename to src/effects/foreground/bubbles.js diff --git a/src/effects/colorLights.js b/src/effects/foreground/colorLights.js similarity index 100% rename from src/effects/colorLights.js rename to src/effects/foreground/colorLights.js diff --git a/src/effects/confetti.js b/src/effects/foreground/confetti.js similarity index 100% rename from src/effects/confetti.js rename to src/effects/foreground/confetti.js diff --git a/src/effects/emojis.js b/src/effects/foreground/emojis.js similarity index 91% rename from src/effects/emojis.js rename to src/effects/foreground/emojis.js index b354d8cc..28d4978b 100644 --- a/src/effects/emojis.js +++ b/src/effects/foreground/emojis.js @@ -1,8 +1,8 @@ -const drawLovestruck = require('../shapes/lovestruck'); -const drawSmiley = require('../shapes/smiley'); -const drawStarstruck = require('../shapes/starstruck'); -const drawTickled = require('../shapes/tickled'); -const drawWink = require('../shapes/wink'); +const drawLovestruck = require('../../shapes/lovestruck'); +const drawSmiley = require('../../shapes/smiley'); +const drawStarstruck = require('../../shapes/starstruck'); +const drawTickled = require('../../shapes/tickled'); +const drawWink = require('../../shapes/wink'); module.exports = function (p5, randomNumber, getInPreviewMode) { return { diff --git a/src/effects/explodingStars.js b/src/effects/foreground/explodingStars.js similarity index 96% rename from src/effects/explodingStars.js rename to src/effects/foreground/explodingStars.js index bb023b9c..03cb810b 100644 --- a/src/effects/explodingStars.js +++ b/src/effects/foreground/explodingStars.js @@ -1,4 +1,4 @@ -const drawStar = require('../shapes/star'); +const drawStar = require('../../shapes/star'); module.exports = function (p5, randomNumber, randomColor, getInPreviewMode) { return { diff --git a/src/effects/floatingRainbows.js b/src/effects/foreground/floatingRainbows.js similarity index 96% rename from src/effects/floatingRainbows.js rename to src/effects/foreground/floatingRainbows.js index 7b66b1bb..1646fc46 100644 --- a/src/effects/floatingRainbows.js +++ b/src/effects/foreground/floatingRainbows.js @@ -1,4 +1,4 @@ -const drawRainbow = require('../shapes/rainbow'); +const drawRainbow = require('../../shapes/rainbow'); module.exports = function (p5, randomNumber, getInPreviewMode) { return { diff --git a/src/effects/heartsColorful.js b/src/effects/foreground/heartsColorful.js similarity index 95% rename from src/effects/heartsColorful.js rename to src/effects/foreground/heartsColorful.js index 236a4abc..d0101523 100644 --- a/src/effects/heartsColorful.js +++ b/src/effects/foreground/heartsColorful.js @@ -1,4 +1,4 @@ -const drawHeart = require('../shapes/heart'); +const drawHeart = require('../../shapes/heart'); module.exports = function (p5, randomNumber, randomColor) { return { diff --git a/src/effects/heartsRed.js b/src/effects/foreground/heartsRed.js similarity index 95% rename from src/effects/heartsRed.js rename to src/effects/foreground/heartsRed.js index c24f2773..e5e7c123 100644 --- a/src/effects/heartsRed.js +++ b/src/effects/foreground/heartsRed.js @@ -1,4 +1,4 @@ -const drawHeart = require('../shapes/heart'); +const drawHeart = require('../../shapes/heart'); module.exports = function (p5, randomNumber) { return { diff --git a/src/effects/musicNotes.js b/src/effects/foreground/musicNotes.js similarity index 96% rename from src/effects/musicNotes.js rename to src/effects/foreground/musicNotes.js index 90eedf6d..1a9090c9 100644 --- a/src/effects/musicNotes.js +++ b/src/effects/foreground/musicNotes.js @@ -1,4 +1,4 @@ -const drawMusicNote = require('../shapes/musicNote'); +const drawMusicNote = require('../../shapes/musicNote'); module.exports = function (p5, randomNumber, getInPreviewMode) { return { diff --git a/src/effects/paintDrip.js b/src/effects/foreground/paintDrip.js similarity index 100% rename from src/effects/paintDrip.js rename to src/effects/foreground/paintDrip.js diff --git a/src/effects/pineapples.js b/src/effects/foreground/pineapples.js similarity index 96% rename from src/effects/pineapples.js rename to src/effects/foreground/pineapples.js index caf3b797..a8f77f5e 100644 --- a/src/effects/pineapples.js +++ b/src/effects/foreground/pineapples.js @@ -1,4 +1,4 @@ -const drawPineapple = require('../shapes/pineapple'); +const drawPineapple = require('../../shapes/pineapple'); module.exports = function (p5, randomNumber, getInPreviewMode) { return { diff --git a/src/effects/pizzas.js b/src/effects/foreground/pizzas.js similarity index 96% rename from src/effects/pizzas.js rename to src/effects/foreground/pizzas.js index 4809c8c3..a115b1bc 100644 --- a/src/effects/pizzas.js +++ b/src/effects/foreground/pizzas.js @@ -1,4 +1,4 @@ -const drawPizza = require('../shapes/pizza'); +const drawPizza = require('../../shapes/pizza'); module.exports = function (p5, randomNumber, getInPreviewMode) { return { diff --git a/src/effects/rain.js b/src/effects/foreground/rain.js similarity index 100% rename from src/effects/rain.js rename to src/effects/foreground/rain.js diff --git a/src/effects/rainingTacos.js b/src/effects/foreground/rainingTacos.js similarity index 97% rename from src/effects/rainingTacos.js rename to src/effects/foreground/rainingTacos.js index e19a5893..b1edbb4a 100644 --- a/src/effects/rainingTacos.js +++ b/src/effects/foreground/rainingTacos.js @@ -1,4 +1,4 @@ -const drawTaco = require('../shapes/taco'); +const drawTaco = require('../../shapes/taco'); module.exports = function (p5, randomNumber, getInPreviewMode) { return { diff --git a/src/effects/smileFace.js b/src/effects/foreground/smileFace.js similarity index 96% rename from src/effects/smileFace.js rename to src/effects/foreground/smileFace.js index f1d13c83..0232e256 100644 --- a/src/effects/smileFace.js +++ b/src/effects/foreground/smileFace.js @@ -1,4 +1,4 @@ -const drawSmiley = require('../shapes/smiley'); +const drawSmiley = require('../../shapes/smiley'); module.exports = function (p5, randomNumber, getInPreviewMode) { return { diff --git a/src/effects/smilingPoop.js b/src/effects/foreground/smilingPoop.js similarity index 96% rename from src/effects/smilingPoop.js rename to src/effects/foreground/smilingPoop.js index 6adb77f8..d97e041e 100644 --- a/src/effects/smilingPoop.js +++ b/src/effects/foreground/smilingPoop.js @@ -1,4 +1,4 @@ -const drawPoop = require('../shapes/poop'); +const drawPoop = require('../../shapes/poop'); module.exports = function (p5, randomNumber, getInPreviewMode) { return { diff --git a/src/effects/spotlight.js b/src/effects/foreground/spotlight.js similarity index 100% rename from src/effects/spotlight.js rename to src/effects/foreground/spotlight.js From 5c6c6b8b5e60dcc6824dc5332581838912aa46d8 Mon Sep 17 00:00:00 2001 From: Ben Brooks Date: Fri, 1 Dec 2023 09:03:31 -0800 Subject: [PATCH 3/3] Add missing semicolon --- src/effects/background/clouds.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/effects/background/clouds.js b/src/effects/background/clouds.js index 61902cf4..83eeebd3 100644 --- a/src/effects/background/clouds.js +++ b/src/effects/background/clouds.js @@ -43,5 +43,5 @@ module.exports = function (p5, lerpColorFromPalette) { }); p5.pop(); }, - } + }; };