Skip to content

Instantly share code, notes, and snippets.

@pketh
Created December 12, 2018 17:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pketh/935bb8347652261effcca22e82ce7640 to your computer and use it in GitHub Desktop.
Save pketh/935bb8347652261effcca22e82ce7640 to your computer and use it in GitHub Desktop.
confetti pours on you after you buy something in glitch/hyperweb
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
"use strict";
/* istanbul ignore next */
module.exports = function(canvas) {
const { PI } = Math;
const { sqrt } = Math;
const { round } = Math;
const { random } = Math;
const { cos } = Math;
const { sin } = Math;
const rAF = window.requestAnimationFrame;
const cAF = window.cancelAnimationFrame || window.cancelRequestAnimationFrame;
const _now = Date.now;
const speed = 50;
const duration = 1.0 / speed;
const confettiRibbonCount = 11;
const ribbonPaperCount = 30;
const ribbonPaperDist = 8.0;
const ribbonPaperThick = 8.0;
const confettiPaperCount = 95;
const DEG_TO_RAD = PI / 180;
const RAD_TO_DEG = 180 / PI;
const colors = [
[
'#df0049',
'#660671'
],
[
'#00e857',
'#005291'
],
[
'#2bebbc',
'#05798a'
],
[
'#ffd200',
'#b06c00'
]
];
var Vector2 = function(_x, _y) {
this.x = _x;
this.y = _y;
this.Length = function() {
return sqrt(this.SqrLength());
};
this.SqrLength = function() {
return (this.x * this.x) + (this.y * this.y);
};
this.Add = function(_vec) {
this.x += _vec.x;
this.y += _vec.y;
};
this.Sub = function(_vec) {
this.x -= _vec.x;
this.y -= _vec.y;
};
this.Div = function(_f) {
this.x /= _f;
this.y /= _f;
};
this.Mul = function(_f) {
this.x *= _f;
this.y *= _f;
};
this.Normalize = function() {
const sqrLen = this.SqrLength();
if (sqrLen !== 0) {
const factor = 1.0 / sqrt(sqrLen);
this.x *= factor;
this.y *= factor;
}
};
this.Normalized = function() {
const sqrLen = this.SqrLength();
if (sqrLen !== 0) {
const factor = 1.0 / sqrt(sqrLen);
return new Vector2(this.x * factor, this.y * factor);
}
return new Vector2(0, 0);
};
};
const EulerMass = function(_x, _y, _mass, _drag) {
this.position = new Vector2(_x, _y);
this.mass = _mass;
this.drag = _drag;
this.force = new Vector2(0, 0);
this.velocity = new Vector2(0, 0);
this.AddForce = function(_f) {
this.force.Add(_f);
};
this.Integrate = function(_dt) {
const acc = this.CurrentForce(this.position);
acc.Div(this.mass);
const posDelta = new Vector2(this.velocity.x, this.velocity.y);
posDelta.Mul(_dt);
this.position.Add(posDelta);
acc.Mul(_dt);
this.velocity.Add(acc);
this.force = new Vector2(0, 0);
};
this.CurrentForce = function(_pos, _vel) {
let speed;
const totalForce = new Vector2(this.force.x, this.force.y);
speed = this.velocity.Length();
const dragVel = new Vector2(this.velocity.x, this.velocity.y);
dragVel.Mul(this.drag * this.mass * speed);
totalForce.Sub(dragVel);
return totalForce;
};
};
var ConfettiPaper = function(_x, _y) {
this.pos = new Vector2(_x, _y);
this.rotationSpeed = (random() * 600) + 800;
this.angle = DEG_TO_RAD * random() * 360;
this.rotation = DEG_TO_RAD * random() * 360;
this.cosA = 1.0;
this.size = 5.0;
this.oscillationSpeed = (random() * 1.5) + 0.5;
this.xSpeed = 40.0;
this.ySpeed = (random() * 60) + 50.0;
this.corners = new Array;
this.time = random();
const ci = round(random() * (colors.length - 1));
this.frontColor = colors[ci][0];
this.backColor = colors[ci][1];
let i = 0;
while (i < 4) {
const dx = cos(this.angle + (DEG_TO_RAD * ((i * 90) + 45)));
const dy = sin(this.angle + (DEG_TO_RAD * ((i * 90) + 45)));
this.corners[i] = new Vector2(dx, dy);
i++;
}
this.Update = function(_dt) {
this.time += _dt;
this.rotation += this.rotationSpeed * _dt;
this.cosA = cos(DEG_TO_RAD * this.rotation);
this.pos.x += cos(this.time * this.oscillationSpeed) * this.xSpeed * _dt;
this.pos.y += this.ySpeed * _dt;
if (this.pos.y > ConfettiPaper.bounds.y) {
this.pos.x = random() * ConfettiPaper.bounds.x;
this.pos.y = 0;
}
};
this.Draw = function(_g) {
let i;
if (this.cosA > 0) {
_g.fillStyle = this.frontColor;
} else {
_g.fillStyle = this.backColor;
}
_g.beginPath();
_g.moveTo((this.pos.x + (this.corners[0].x * this.size)), (this.pos.y + (this.corners[0].y * this.size * this.cosA)));
i = 1;
while (i < 4) {
_g.lineTo((this.pos.x + (this.corners[i].x * this.size)), (this.pos.y + (this.corners[i].y * this.size * this.cosA)));
i++;
}
_g.closePath();
_g.fill();
};
};
var ConfettiRibbon = function(_x, _y, _count, _dist, _thickness, _angle, _mass, _drag) {
this.particleDist = _dist;
this.particleCount = _count;
this.particleMass = _mass;
this.particleDrag = _drag;
this.particles = new Array;
const ci = round(random() * (colors.length - 1));
this.frontColor = colors[ci][0];
this.backColor = colors[ci][1];
this.xOff = cos(DEG_TO_RAD * _angle) * _thickness;
this.yOff = sin(DEG_TO_RAD * _angle) * _thickness;
this.position = new Vector2(_x, _y);
this.prevPosition = new Vector2(_x, _y);
this.velocityInherit = (random() * 2) + 4;
this.time = random() * 100;
this.oscillationSpeed = (random() * 2) + 2;
this.oscillationDistance = (random() * 40) + 40;
this.ySpeed = (random() * 40) + 80;
let i = 0;
while (i < this.particleCount) {
this.particles[i] = new EulerMass(_x, _y - (i * this.particleDist), this.particleMass, this.particleDrag);
i++;
}
this.Update = function(_dt) {
let i;
i = 0;
this.time += _dt * this.oscillationSpeed;
this.position.y += this.ySpeed * _dt;
this.position.x += cos(this.time) * this.oscillationDistance * _dt;
this.particles[0].position = this.position;
const dX = this.prevPosition.x - (this.position.x);
const dY = this.prevPosition.y - (this.position.y);
const delta = sqrt((dX * dX) + (dY * dY));
this.prevPosition = new Vector2(this.position.x, this.position.y);
i = 1;
while (i < this.particleCount) {
const dirP = Vector2.Sub(this.particles[i - 1].position, this.particles[i].position);
dirP.Normalize();
dirP.Mul((delta / _dt) * this.velocityInherit);
this.particles[i].AddForce(dirP);
i++;
}
i = 1;
while (i < this.particleCount) {
this.particles[i].Integrate(_dt);
i++;
}
i = 1;
while (i < this.particleCount) {
const rp2 = new Vector2(this.particles[i].position.x, this.particles[i].position.y);
rp2.Sub(this.particles[i - 1].position);
rp2.Normalize();
rp2.Mul(this.particleDist);
rp2.Add(this.particles[i - 1].position);
this.particles[i].position = rp2;
i++;
}
if (this.position.y > (ConfettiRibbon.bounds.y + (this.particleDist * this.particleCount))) {
this.Reset();
}
};
this.Reset = function() {
let ci;
let i;
this.position.y = -random() * ConfettiRibbon.bounds.y;
this.position.x = random() * ConfettiRibbon.bounds.x;
this.prevPosition = new Vector2(this.position.x, this.position.y);
this.velocityInherit = (random() * 2) + 4;
this.time = random() * 100;
this.oscillationSpeed = (random() * 2.0) + 1.5;
this.oscillationDistance = (random() * 40) + 40;
this.ySpeed = (random() * 40) + 80;
ci = round(random() * (colors.length - 1));
this.frontColor = colors[ci][0];
this.backColor = colors[ci][1];
this.particles = new Array;
i = 0;
while (i < this.particleCount) {
this.particles[i] = new EulerMass(this.position.x, this.position.y - (i * this.particleDist), this.particleMass, this.particleDrag);
i++;
}
};
this.Draw = function(_g) {
let i;
i = 0;
while (i < (this.particleCount - 1)) {
const p0 = new Vector2(this.particles[i].position.x + this.xOff, this.particles[i].position.y + this.yOff);
const p1 = new Vector2(this.particles[i + 1].position.x + this.xOff, this.particles[i + 1].position.y + this.yOff);
if (this.Side(this.particles[i].position.x, this.particles[i].position.y, this.particles[i + 1].position.x, this.particles[i + 1].position.y, p1.x, p1.y) < 0) {
_g.fillStyle = this.frontColor;
_g.strokeStyle = this.frontColor;
} else {
_g.fillStyle = this.backColor;
_g.strokeStyle = this.backColor;
}
if (i === 0) {
_g.beginPath();
_g.moveTo(this.particles[i].position.x, this.particles[i].position.y);
_g.lineTo(this.particles[i + 1].position.x, this.particles[i + 1].position.y);
_g.lineTo((this.particles[i + 1].position.x + p1.x) * 0.5, (this.particles[i + 1].position.y + p1.y) * 0.5);
_g.closePath();
_g.stroke();
_g.fill();
_g.beginPath();
_g.moveTo(p1.x, p1.y);
_g.lineTo(p0.x, p0.y);
_g.lineTo((this.particles[i + 1].position.x + p1.x) * 0.5, (this.particles[i + 1].position.y + p1.y) * 0.5);
_g.closePath();
_g.stroke();
_g.fill();
} else if (i === (this.particleCount - 2)) {
_g.beginPath();
_g.moveTo(this.particles[i].position.x, this.particles[i].position.y);
_g.lineTo(this.particles[i + 1].position.x, this.particles[i + 1].position.y);
_g.lineTo((this.particles[i].position.x + p0.x) * 0.5, (this.particles[i].position.y + p0.y) * 0.5);
_g.closePath();
_g.stroke();
_g.fill();
_g.beginPath();
_g.moveTo(p1.x, p1.y);
_g.lineTo(p0.x, p0.y);
_g.lineTo((this.particles[i].position.x + p0.x) * 0.5, (this.particles[i].position.y + p0.y) * 0.5);
_g.closePath();
_g.stroke();
_g.fill();
} else {
_g.beginPath();
_g.moveTo(this.particles[i].position.x, this.particles[i].position.y);
_g.lineTo(this.particles[i + 1].position.x, this.particles[i + 1].position.y);
_g.lineTo(p1.x, p1.y);
_g.lineTo(p0.x, p0.y);
_g.closePath();
_g.stroke();
_g.fill();
}
i++;
}
};
this.Side = (x1, y1, x2, y2, x3, y3) => ((x1 - x2) * (y3 - y2)) - ((y1 - y2) * (x3 - x2));
};
Vector2.Lerp = (_vec0, _vec1, _t) => new Vector2(((_vec1.x - (_vec0.x)) * _t) + _vec0.x, ((_vec1.y - (_vec0.y)) * _t) + _vec0.y);
Vector2.Distance = (_vec0, _vec1) => sqrt(Vector2.SqrDistance(_vec0, _vec1));
Vector2.SqrDistance = function(_vec0, _vec1) {
const x = _vec0.x - (_vec1.x);
const y = _vec0.y - (_vec1.y);
return (x * x) + (y * y) + (z * z);
};
Vector2.Scale = (_vec0, _vec1) => new Vector2(_vec0.x * _vec1.x, _vec0.y * _vec1.y);
Vector2.Min = (_vec0, _vec1) => new Vector2(Math.min(_vec0.x, _vec1.x), Math.min(_vec0.y, _vec1.y));
Vector2.Max = (_vec0, _vec1) => new Vector2(Math.max(_vec0.x, _vec1.x), Math.max(_vec0.y, _vec1.y));
Vector2.ClampMagnitude = function(_vec0, _len) {
const vecNorm = _vec0.Normalized;
return new Vector2(vecNorm.x * _len, vecNorm.y * _len);
};
Vector2.Sub = (_vec0, _vec1) => new Vector2(_vec0.x - (_vec1.x), _vec0.y - (_vec1.y), _vec0.z - (_vec1.z));
ConfettiPaper.bounds = new Vector2(0, 0);
ConfettiRibbon.bounds = new Vector2(0, 0);
let confetti = {};
confetti.Context = function(canvas) {
let i = 0;
const canvasParent = window;
let canvasWidth = canvasParent.innerWidth;
let canvasHeight = canvasParent.innerHeight;
canvas.width = canvasWidth;
canvas.height = canvasHeight;
const context = canvas.getContext('2d');
const interval = null;
const confettiRibbons = new Array;
ConfettiRibbon.bounds = new Vector2(canvasWidth, canvasHeight);
i = 0;
while (i < confettiRibbonCount) {
confettiRibbons[i] = new ConfettiRibbon(random() * canvasWidth, -random() * canvasHeight * 2, ribbonPaperCount, ribbonPaperDist, ribbonPaperThick, 45, 1, 0.05);
i++;
}
const confettiPapers = new Array;
ConfettiPaper.bounds = new Vector2(canvasWidth, canvasHeight);
i = 0;
while (i < confettiPaperCount) {
confettiPapers[i] = new ConfettiPaper(random() * canvasWidth, random() * canvasHeight);
i++;
}
this.resize = function() {
canvasWidth = canvasParent.innerWidth;
canvasHeight = canvasParent.innerHeight;
canvas.width = canvasWidth;
canvas.height = canvasHeight;
ConfettiPaper.bounds = new Vector2(canvasWidth, canvasHeight);
ConfettiRibbon.bounds = new Vector2(canvasWidth, canvasHeight);
};
this.start = function() {
let context;
this.stop();
context = this;
this.update();
};
this.stop = function() {
cAF(this.interval);
};
this.update = function() {
let i;
i = 0;
context.clearRect(0, 0, canvas.width, canvas.height);
i = 0;
while (i < confettiPaperCount) {
confettiPapers[i].Update(duration);
confettiPapers[i].Draw(context);
i++;
}
i = 0;
while (i < confettiRibbonCount) {
confettiRibbons[i].Update(duration);
confettiRibbons[i].Draw(context);
i++;
}
this.interval = rAF(function() {
confetti.update();
});
};
};
confetti = new (confetti.Context)(canvas);
confetti.start();
window.addEventListener('resize', function(event) {
confetti.resize();
});
return confetti;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment