My contribution to this month's Creative Coding Club challenge.
I used this month's challenge to learn and get comfortable with Matter.js and P5.js.
A Pen by Mariusz Dabrowski on CodePen.
My contribution to this month's Creative Coding Club challenge.
I used this month's challenge to learn and get comfortable with Matter.js and P5.js.
A Pen by Mariusz Dabrowski on CodePen.
| <div class="instructions"> | |
| Click and drag Sticky the marshmallow!<br> | |
| See how it was built <a href="https://codepen.io/MarioD/post/hot-and-sticky-the-process" target="_blank">here</a>. | |
| </div> | |
| <div class="height-warning"></div> |
| // Module aliases | |
| var Engine = Matter.Engine, | |
| World = Matter.World, | |
| Bodies = Matter.Bodies, | |
| Body = Matter.Body, | |
| Constraint = Matter.Constraint, | |
| Composite = Matter.Composite, | |
| Composites = Matter.Composites, | |
| MouseConstraint = Matter.MouseConstraint, | |
| Mouse = Matter.Mouse, | |
| Events = Matter.Events, | |
| Vertices = Matter.Vertices; | |
| var engine = Engine.create(); | |
| var world = engine.world; | |
| var floor; | |
| var cup; | |
| var cupLeft; | |
| var cupRight; | |
| var cupHandle; | |
| var chain = null; | |
| var heatLines = []; | |
| var distanceToCup = 10000; | |
| var distanceFromCup = {size: 500, towards: true}; | |
| var firstAnimation = {max: 241, min: 171, percent: 1}; | |
| var secondAnimation = {max: 170, min: 100, percent: 0}; | |
| var thirdAnimation = {max: 241, min: 100, percent: 0}; | |
| // --------------- | |
| // Box Constructor | |
| // --------------- | |
| function Box(x, y, w, h, options) { | |
| this.w = w; | |
| this.h = h; | |
| this.body = Bodies.rectangle(x, y, w, h, options); | |
| World.add(world, this.body); | |
| } | |
| // | |
| function calculateLinks() { | |
| // 77 is the offset from the bottom and the top | |
| // 200 is the amount of space we want between the marshmallow and cup when hanging | |
| var spaceLeft = window.innerHeight - (125 + 100 + 77 + 200); | |
| var links = spaceLeft / 26; | |
| if(links < 3) { | |
| return Math.ceil(3); | |
| } else if(links > 6) { | |
| return Math.ceil(6); | |
| } else { | |
| return Math.ceil(links); | |
| } | |
| } | |
| // ------------ | |
| // Create chain | |
| // ------------ | |
| function CreateChain(x, y, chainLinks, linkLength) { | |
| this.x = x; | |
| this.y = y; | |
| this.hinges = []; | |
| this.constraints = []; | |
| this.chainLinks = chainLinks; | |
| this.linkLength = linkLength; | |
| } | |
| CreateChain.prototype.remove = function() { | |
| for(var i = 0; i < this.constraints.length; i++) { | |
| World.remove(world, this.constraints[i]); | |
| } | |
| chain = null; | |
| } | |
| CreateChain.prototype.init = function() { | |
| // Create hinges | |
| for(var i = 0; i < this.chainLinks; i++) { | |
| var static = (i === 0) ? true : false ; | |
| var anchor = new Box(this.x, this.y + (this.linkLength * i), 5, 5, { | |
| isStatic: static, | |
| collisionFilter: { | |
| category: 0x0001 | |
| } | |
| }); | |
| this.hinges.push(anchor); | |
| } | |
| // Create links between hinges | |
| for(var i = 0; i < this.hinges.length; i++) { | |
| var constraint; | |
| if(i === this.chainLinks - 1) { | |
| constraint = Constraint.create({ | |
| bodyA: this.hinges[i].body, | |
| bodyB: marshmallow.body, | |
| pointB: { x: 0, y: (marshmallow.h/2 * -1) + 12 }, | |
| length: this.linkLength, | |
| damping: 0.5, | |
| stiffness: 0.1, | |
| label: 'marshmallowAttachment' | |
| }); | |
| } else { | |
| constraint = Constraint.create({ | |
| bodyA: this.hinges[i].body, | |
| bodyB: this.hinges[i + 1].body, | |
| length: this.linkLength, | |
| damping: 0.5, | |
| stiffness: 0.1 | |
| }); | |
| } | |
| this.constraints.push(constraint); | |
| World.add(world, constraint); | |
| } | |
| } | |
| function createChain() { | |
| chain = new CreateChain(width/2, 50, calculateLinks(), 10); | |
| chain.init(); | |
| } | |
| // -------------- | |
| // Heat particles | |
| // -------------- | |
| function HeatParticle(x, y) { | |
| this.position = createVector(x, y); | |
| this.index = 0; | |
| } | |
| HeatParticle.prototype.render = function() { | |
| push(); | |
| noStroke(); | |
| fill('#f0d38d'); | |
| ellipse(this.position.x, this.position.y, this.parent.particleSize); | |
| pop(); | |
| } | |
| HeatParticle.prototype.updatePos = function() { | |
| this.position.y -= 0.5; | |
| this.position.x = Math.sin((frameCount + this.index/0.4) / 35) * 10 + this.parent.position.x; | |
| } | |
| HeatParticle.prototype.checkPos = function() { | |
| if(this.position.y < this.parent.position.y - this.parent.height) { | |
| this.reset(); | |
| } | |
| } | |
| HeatParticle.prototype.reset = function() { | |
| this.parent.particleIndex += 1; | |
| this.index = this.parent.particleIndex; | |
| this.position.y = this.parent.position.y; | |
| } | |
| // ---------- | |
| // Heat lines | |
| // ---------- | |
| function HeatLine(x, y, height, particleSize) { | |
| this.position = createVector(x, y); | |
| this.particles = []; | |
| this.particleIndex = 0; | |
| this.height = height; | |
| this.particleSize = particleSize; | |
| } | |
| HeatLine.prototype.render = function() { | |
| for(var i = 0; i < this.particles.length; i++) { | |
| this.particles[i].updatePos(); | |
| this.particles[i].render(); | |
| this.particles[i].checkPos(); | |
| } | |
| } | |
| HeatLine.prototype.init = function() { | |
| var particleCount = this.height / (this.particleSize / 6); | |
| for(var i = 0; i < particleCount; i++) { | |
| this.particleIndex += 1; | |
| var particle = new HeatParticle(this.position.x, this.position.y + (i * this.particleSize / 6)); | |
| particle.index = this.particleIndex; | |
| particle.parent = this; | |
| this.particles.push(particle); | |
| } | |
| } | |
| function populateHeatLines() { | |
| heatLines.push(new HeatLine(cup.body.position.x, cup.body.position.y - cup.h/2, 50, 5)); | |
| heatLines.push(new HeatLine(cup.body.position.x - 60, cup.body.position.y - cup.h/2, 50, 5)); | |
| heatLines.push(new HeatLine(cup.body.position.x + 60, cup.body.position.y - cup.h/2, 50, 5)); | |
| for(var i = 0; i < heatLines.length; i++) { | |
| heatLines[i].init(); | |
| } | |
| } | |
| // ----------- | |
| // Cup + Floor | |
| // ----------- | |
| // Change this to an object since we don't need it to construct anything | |
| function CupFloor() {} | |
| CupFloor.prototype.destroy = function() { | |
| World.remove(world, [ | |
| floor.body, | |
| cup.body, | |
| cupLeft.body, | |
| cupRight.body, | |
| cupHandle.body, | |
| ]); | |
| floor = null; | |
| cup = null; | |
| cupLeft = null; | |
| cupRight = null; | |
| cupHandle = null; | |
| } | |
| CupFloor.prototype.init = function() { | |
| // All of the magic numbers here are to position the elements relative to the marshmallow body | |
| floor = new Box(width/2, height - 31.75, 320, 3.5, {isStatic: true, collisionFilter: {category: 0x0002}}); | |
| cup = new Box(width/2, height - 93, 259, 125.5, {isStatic: true, isSensor: true, label: 'cup', collisionFilter: {category: 0x0002}}); | |
| cupLeft = new Box(width/2 - 134.5, height - 93, 10, 125.5, {isStatic: true, collisionFilter: {category: 0x0002}}); | |
| cupRight = new Box(width/2 + 134.5, height - 93, 10, 125.5, {isStatic: true, collisionFilter: {category: 0x0002}}); | |
| cupHandle = new Box(width/2 + 153, height - 114, 31, 60.5, {isStatic: true, collisionFilter: {category: 0x0002}}); | |
| } | |
| var cupFloor = new CupFloor(); | |
| // --------- | |
| // P5 Resize | |
| // --------- | |
| function windowResized() { | |
| resizeCanvas(windowWidth, windowHeight); | |
| cupFloor.destroy(); | |
| cupFloor.init(); | |
| heatLines = []; | |
| populateHeatLines(); | |
| marshmallow.body.isStatic = true; | |
| marshmallow.body.angle = 0; | |
| if(chain) { | |
| chain.remove(); | |
| } | |
| createChain(); | |
| marshmallow.body.isStatic = false; | |
| Body.setVelocity(marshmallow.body, { | |
| x: 0, | |
| y: 0 | |
| }); | |
| marshmallow.angularVelocity = 0; | |
| marshmallow.angularSpeed = 0; | |
| firstAnimation.percent = 0; | |
| secondAnimation.percent = 0; | |
| thirdAnimation.percent = 0; | |
| } | |
| // -------- | |
| // P5 Setup | |
| // -------- | |
| function setup() { | |
| // Setup the canvas | |
| var canvas = createCanvas(windowWidth, windowHeight); | |
| rectMode(CENTER); | |
| // Setup the mouse events | |
| var mouse = Mouse.create(canvas.elt); | |
| mouse.pixelRatio = pixelDensity(); | |
| var mouseConstraint = MouseConstraint.create(engine, {mouse: mouse, constraint: {stiffness: 0.2}}); | |
| mouseConstraint.collisionFilter.category = 0x0002; | |
| World.add(world, mouseConstraint); | |
| // Load all of the image assets | |
| marshmallowBody = loadImage('https://s3-us-west-2.amazonaws.com/s.cdpn.io/49240/body.png'); | |
| floorImg = loadImage('https://s3-us-west-2.amazonaws.com/s.cdpn.io/49240/ground.png'); | |
| cupImg = loadImage('https://s3-us-west-2.amazonaws.com/s.cdpn.io/49240/cup.png'); | |
| cupHandleImg = loadImage('https://s3-us-west-2.amazonaws.com/s.cdpn.io/49240/cupHandle.png'); | |
| // Create the boundaries | |
| cupFloor.init(); | |
| // ----------- | |
| // Marshmallow | |
| // ----------- | |
| // The marshmallow code below is very messy and should be refactored into a constructor | |
| marshmallow = new Box(width/2, 0, 80, 100, { | |
| density: 0.00001, | |
| label: 'marshmallow', | |
| collisionFilter: { | |
| category: 0x0001, | |
| mask: 0x0002 | |
| } | |
| }); | |
| createChain(); | |
| armLeft = Bodies.circle(width/2 - 40, 300, 5, { | |
| collisionFilter: { | |
| category: 0x0001 | |
| }, | |
| density: 0.00001 | |
| }); | |
| armRight = Bodies.circle(width/2 + 40, 300, 5, { | |
| collisionFilter: { | |
| category: 0x0001 | |
| }, | |
| density: 0.00001 | |
| }); | |
| var legRight = Bodies.circle(width/2 + 20, 300 + 50, 0.1, { | |
| collisionFilter: { | |
| category: 0x0001 | |
| }, | |
| density: 0.00001 | |
| }); | |
| var legLeft = Bodies.circle(width/2 - 20, 300 + 50, 0.1, { | |
| collisionFilter: { | |
| category: 0x0001 | |
| }, | |
| density: 0.00001 | |
| }); | |
| constraintArmLeft = Constraint.create({ | |
| bodyA: marshmallow.body, | |
| bodyB: armLeft, | |
| pointA: { x: -39, y: -20 }, | |
| length: 40, | |
| damping: 0.5, | |
| stiffness: 1, | |
| label: 'limb' | |
| }); | |
| constraintArmRight = Constraint.create({ | |
| bodyA: marshmallow.body, | |
| bodyB: armRight, | |
| pointA: { x: 39, y: -20 }, | |
| length: 40, | |
| damping: 0.5, | |
| stiffness: 1, | |
| label: 'limb' | |
| }); | |
| constraintLegRight = Constraint.create({ | |
| bodyA: marshmallow.body, | |
| bodyB: legRight, | |
| pointA: { x: 20, y: 49 }, | |
| length: 30, | |
| damping: 0.5, | |
| stiffness: 1, | |
| label: 'limb' | |
| }); | |
| constraintLegLeft = Constraint.create({ | |
| bodyA: marshmallow.body, | |
| bodyB: legLeft, | |
| pointA: { x: -20, y: 49 }, | |
| length: 30, | |
| damping: 0.5, | |
| stiffness: 1, | |
| label: 'limb' | |
| }); | |
| World.add(world, [ | |
| armLeft, | |
| armRight, | |
| legRight, | |
| legLeft, | |
| constraintArmLeft, | |
| constraintArmRight, | |
| constraintLegRight, | |
| constraintLegLeft | |
| ]); | |
| // Create and initialize the heat lines | |
| populateHeatLines(); | |
| // Start the engine | |
| Engine.run(engine); | |
| } | |
| // ------- | |
| // P5 Draw | |
| // ------- | |
| function draw() { | |
| clear(); | |
| // ---------------------- | |
| // Outline matter objects | |
| // ---------------------- | |
| // push(); | |
| // var bodies = Composite.allBodies(engine.world); | |
| // | |
| // drawingContext.beginPath(); | |
| // for (var i = 0; i < bodies.length; i += 1) { | |
| // var vertices = bodies[i].vertices; | |
| // drawingContext.moveTo(vertices[0].x, vertices[0].y); | |
| // for (var j = 1; j < vertices.length; j += 1) { | |
| // drawingContext.lineTo(vertices[j].x, vertices[j].y); | |
| // } | |
| // drawingContext.lineTo(vertices[0].x, vertices[0].y); | |
| // } | |
| // | |
| // drawingContext.lineWidth = 1; | |
| // drawingContext.strokeStyle = '#9e9e9e'; | |
| // drawingContext.stroke(); | |
| // pop(); | |
| if(cup) { | |
| // heatLines | |
| for(var i = 0; i < heatLines.length; i++) { | |
| heatLines[i].render(); | |
| } | |
| } | |
| // -------------------- | |
| // Draw the marshmallow | |
| // -------------------- | |
| push(); | |
| translate(marshmallow.body.position.x, marshmallow.body.position.y); | |
| rotate(marshmallow.body.angle); | |
| image(marshmallowBody, marshmallow.w/2 * -1, marshmallow.h/2 * -1, marshmallow.w, marshmallow.h); | |
| pop(); | |
| // -------------- | |
| // Draw the chain | |
| // -------------- | |
| var allConstraints = Composite.allConstraints(engine.world); | |
| var marshmallowAttachment; | |
| // Rope hole at the top of the page | |
| if(chain) { | |
| push(); | |
| noStroke(); | |
| fill('black'); | |
| ellipse(chain.x, chain.y, 25, 6); | |
| pop(); | |
| } | |
| for(var i = 0; i < allConstraints.length; i++) { | |
| if(allConstraints[i].label === 'marshmallowAttachment') { | |
| marshmallowAttachment = allConstraints[i]; | |
| } | |
| if(allConstraints[i].label !== 'Mouse Constraint') { | |
| push(); | |
| strokeWeight(2.5); | |
| line( | |
| allConstraints[i].bodyA.position.x + allConstraints[i].pointA.x, | |
| allConstraints[i].bodyA.position.y + allConstraints[i].pointA.y, | |
| allConstraints[i].bodyB.position.x + allConstraints[i].pointB.x, | |
| allConstraints[i].bodyB.position.y + allConstraints[i].pointB.y | |
| ); | |
| pop(); | |
| } | |
| } | |
| // Rope attachment on top of head | |
| if(marshmallowAttachment) { | |
| push(); | |
| noStroke(); | |
| fill('black'); | |
| translate(marshmallowAttachment.bodyB.position.x + marshmallowAttachment.pointB.x, marshmallowAttachment.bodyB.position.y + marshmallowAttachment.pointB.y); | |
| rotate(marshmallow.body.angle); | |
| ellipse(0, 0, 10, 3); | |
| pop(); | |
| } | |
| // Draw arms | |
| push(); | |
| strokeWeight(2.5); | |
| ellipse(armLeft.position.x, armLeft.position.y, 10); | |
| ellipse(armRight.position.x, armRight.position.y, 10); | |
| pop(); | |
| // When the arms enter the cup, raise them | |
| if(cup) { | |
| if(marshmallow.body.position.y / height > 0.75 && marshmallow.body.position.x > cup.body.position.x - cup.w/2 && marshmallow.body.position.x < cup.body.position.x + cup.w/2) { | |
| Matter.Body.setVelocity(armLeft, { x: 0, y: -3 }) | |
| Matter.Body.setVelocity(armRight, { x: 0, y: -3 }) | |
| } | |
| } | |
| // Facial expression | |
| if(cup) { | |
| distanceToCup = Math.sqrt(Math.pow(marshmallow.body.position.x - cup.body.position.x, 2) + Math.pow(marshmallow.body.position.y - cup.body.position.y, 2)); | |
| } else { | |
| distanceToCup = 1000; | |
| } | |
| if(distanceToCup <= firstAnimation.max && distanceToCup >= firstAnimation.min) { | |
| firstAnimation.percent = (distanceToCup - firstAnimation.min) / (firstAnimation.max - firstAnimation.min); | |
| } | |
| if(distanceToCup < secondAnimation.max && distanceToCup >= secondAnimation.min) { | |
| secondAnimation.percent = ((distanceToCup - secondAnimation.min) / (secondAnimation.max - secondAnimation.min) - 1) * -1; | |
| } | |
| if(distanceToCup < thirdAnimation.max && distanceToCup >= thirdAnimation.min) { | |
| thirdAnimation.percent = ((distanceToCup - thirdAnimation.min) / (thirdAnimation.max - thirdAnimation.min) - 1) * -1; | |
| } | |
| if(distanceToCup < secondAnimation.max) { | |
| firstAnimation.percent = 0; | |
| } | |
| if(distanceToCup > firstAnimation.max) { | |
| firstAnimation.percent = 1; | |
| secondAnimation.percent = 0; | |
| } | |
| // Marshmallow eye left | |
| push(); | |
| translate(marshmallow.body.position.x, marshmallow.body.position.y); | |
| strokeWeight(3); | |
| noFill(); | |
| rotate(marshmallow.body.angle); | |
| bezier( | |
| -20, -5 + (secondAnimation.percent * 5) + (secondAnimation.percent * -4), | |
| -20, -5 + (firstAnimation.percent * -7) + (secondAnimation.percent * 5) + (secondAnimation.percent * -4), | |
| -10, -5 + (firstAnimation.percent * -7) + (secondAnimation.percent * -4), | |
| -10, -5 + (secondAnimation.percent * -4) | |
| ); | |
| pop(); | |
| // Marshmallow eye right | |
| // The second parameter, (secondAnimation.percent * -4), is to move the item up when the animation happens | |
| push(); | |
| translate(marshmallow.body.position.x, marshmallow.body.position.y); | |
| strokeWeight(3); | |
| noFill(); | |
| rotate(marshmallow.body.angle); | |
| bezier( | |
| 20, -5 + (secondAnimation.percent * 5) + (secondAnimation.percent * -4), | |
| 20, -5 + (firstAnimation.percent * -7) + (secondAnimation.percent * 5) + (secondAnimation.percent * -4), | |
| 10, -5 + (firstAnimation.percent * -7) + (secondAnimation.percent * -4), | |
| 10, -5 + (secondAnimation.percent * -4) | |
| ); | |
| pop(); | |
| // Marshmallow mouth | |
| push(); | |
| stroke('#000'); | |
| strokeJoin(ROUND); | |
| strokeWeight(2); | |
| fill('black'); | |
| translate(marshmallow.body.position.x, marshmallow.body.position.y); | |
| rotate(marshmallow.body.angle); | |
| arc(0, 12 + (thirdAnimation.percent * 5), 16, firstAnimation.percent * 14, 0, 3.14, CHORD); | |
| arc(0, 12 + (thirdAnimation.percent * 5), 16, thirdAnimation.percent * 14, 3.14, 0, CHORD); | |
| pop(); | |
| // --- | |
| // Cup | |
| // --- | |
| if(cup) { | |
| push(); | |
| noStroke(); | |
| fill('#fee096'); | |
| translate(cup.body.position.x, cup.body.position.y); | |
| rect(0, 60, cup.w + 20, cup.h + 100); | |
| pop(); | |
| push(); | |
| translate(floor.body.position.x, floor.body.position.y); | |
| image(floorImg, floor.w/2 * -1, floor.h/2 * -1, floor.w, floor.h); | |
| pop(); | |
| push(); | |
| translate(cup.body.position.x, cup.body.position.y); | |
| image(cupImg, (cup.w/2 * -1) - 10, cup.h/2 * -1, cup.w + 20, cup.h); | |
| pop(); | |
| push(); | |
| noFill(); | |
| noStroke(); | |
| translate(cupHandle.body.position.x, cupHandle.body.position.y); | |
| image(cupHandleImg, cupHandle.w/2 * -1, cupHandle.h/2 * -1, cupHandle.w, cupHandle.h); | |
| pop(); | |
| // Outer eye Left | |
| push(); | |
| noStroke(); | |
| fill('white'); | |
| translate(cup.body.position.x - 76.5, cup.body.position.y - 5.5); | |
| ellipse(0, 0, 34); | |
| rotate(thirdAnimation.percent * 1.3); | |
| stroke('#812d29'); | |
| strokeWeight(3.5); | |
| line(-24, 2, 2, -24); | |
| pop(); | |
| // Outer eye right | |
| push(); | |
| noStroke(); | |
| fill('white'); | |
| translate(cup.body.position.x + 76.5, cup.body.position.y - 5.5); | |
| ellipse(0, 0, 34); | |
| rotate(thirdAnimation.percent * -1.3); | |
| stroke('#812d29'); | |
| strokeWeight(3.5); | |
| line(24, -2, -2, -24); | |
| pop(); | |
| // Cheek right | |
| push(); | |
| noStroke(); | |
| fill('#f6554f'); | |
| translate(cup.body.position.x + 76.5, cup.body.position.y); | |
| ellipse(0, 10 + thirdAnimation.percent * 3, 34, 10); | |
| pop(); | |
| // Cheek left | |
| push(); | |
| noStroke(); | |
| fill('#ff635b'); | |
| translate(cup.body.position.x - 76.5, cup.body.position.y); | |
| ellipse(0, 10 + thirdAnimation.percent * 3, 34, 10); | |
| pop(); | |
| // Blush left | |
| push(); | |
| noStroke(); | |
| fill('#ff847e'); | |
| translate(cup.body.position.x - 76.5, cup.body.position.y); | |
| ellipse(-20, 18.5, 18.5, 11); | |
| pop(); | |
| // Blush right | |
| push(); | |
| noStroke(); | |
| fill('#ff635b'); | |
| translate(cup.body.position.x + 76.5, cup.body.position.y); | |
| ellipse(20, 18.5, 18.5, 11); | |
| pop(); | |
| // Inner eyes | |
| push(); | |
| noStroke(); | |
| fill('black'); | |
| translate(cup.body.position.x, cup.body.position.y); | |
| ellipse( | |
| -76.5 + (marshmallow.body.position.x / width - 0.5) * 10, | |
| -7 + (marshmallow.body.position.y / height - 0.5) * 10, | |
| 9.5 | |
| ); | |
| ellipse( | |
| 76.5 + (marshmallow.body.position.x / width - 0.5) * 10, | |
| -7 + (marshmallow.body.position.y / height - 0.5) * 10, | |
| 9.5 | |
| ); | |
| pop(); | |
| // Cup mouth | |
| push(); | |
| stroke('#812d29'); | |
| strokeJoin(ROUND); | |
| strokeWeight(2); | |
| fill('#812d29'); | |
| translate(cup.body.position.x, cup.body.position.y); | |
| rotate(cup.body.angle); | |
| arc(0, -10 + (thirdAnimation.percent * 18), 46, firstAnimation.percent * 44, 0, 3.14, CHORD); | |
| arc(0, -10 + (thirdAnimation.percent * 18), 46, thirdAnimation.percent * 44, 3.14, 0, CHORD); | |
| pop(); | |
| } | |
| } |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.11/p5.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.12.0/matter.min.js"></script> |
| /* apply a natural box layout model to all elements, but allowing components to change */ | |
| html { | |
| box-sizing: border-box; | |
| } | |
| *, | |
| *:before, | |
| *:after { | |
| box-sizing: inherit; | |
| } | |
| body { | |
| background: #fee096; | |
| } | |
| canvas { | |
| display: block; | |
| width: 100%; | |
| height: 100%; | |
| } | |
| .height-warning { | |
| width: 100%; | |
| height: 100%; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| background: #fee096 url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/49240/height.png) center no-repeat; | |
| background-size: auto 40%; | |
| opacity: 0; | |
| transition: opacity 0.4s; | |
| pointer-events: none; | |
| z-index: 10; | |
| } | |
| @media(max-height: 499px) { | |
| .height-warning { | |
| opacity: 1; | |
| } | |
| } | |
| .instructions { | |
| display: none; | |
| line-height: 26px; | |
| } | |
| .instructions a { | |
| color: #7f6e4a; | |
| } | |
| @media(min-width: 768px) { | |
| .instructions { | |
| z-index: 5; | |
| position: absolute; | |
| top: 20px; | |
| left: 20px; | |
| color: #b79e6a; | |
| display: block; | |
| font-family: 'Open Sans', sans-serif; | |
| font-weight: 300; | |
| font-size: 13px; | |
| letter-spacing: 0.010em; | |
| } | |
| } |