{"__browser":{"country":"US","device":"unknown_device","mobile":false,"name":"unknown browser","platform":"unknown_platform","version":"0"},"__constants":{},"__CPDATA":{"domain_iframe":"https://cdpn.io","environment":"production","host":"codepen.io","iframe_allow":"accelerometer; ambient-light-sensor; camera; display-capture; encrypted-media; geolocation; gyroscope; microphone; midi; payment; vr; web-share","iframe_sandbox":"allow-forms allow-modals allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-top-navigation-by-user-activation allow-downloads allow-presentation"},"__graphql":{"data":{"data":{"sessionUser":{"id":"VoDkNZ","name":"Captain Anonymous","title":"Captain Anonymous","avatar":"https://assets.codepen.io/t-1/user-default-avatar.jpg?format=auto&version=0","currentContext":{"id":"VoDkNZ","title":"Captain Anonymous","name":"Captain Anonymous","avatar":"https://assets.codepen.io/t-1/user-default-avatar.jpg?format=auto&version=0","username":"anon","__typename":"User"},"currentTeamId":null,"username":"anon","admin":false,"anon":true,"pro":false,"verified":false,"teams":[],"__typename":"User"}}},"url":"https://codepen.io/graphql","api":"cprails"},"__user":{"anon":true,"base_url":"/anon/","cohorts":[],"current_team_hashid":null,"current_team_id":0,"hashid":"VoDkNZ","id":1,"itemType":"user","name":"Captain Anonymous","paid":false,"tier":0,"username":"anon","created_at":null,"email_verified":null,"collections_count":0,"collections_private_count":0,"followers_count":0,"followings_count":0,"pens_count":0,"pens_private_count":0,"projects_count":0,"projects_private_count":0},"__firebase":{"config":{"apiKey":"AIzaSyBgLAe7N_MdFpuVofMkcQLGwwhUu5tuxls","authDomain":"codepen-store-production.firebaseapp.com","databaseURL":"https://codepen-store-production.firebaseio.com","disabled":false,"projectId":"codepen-store-production"},"token":"eyJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJodHRwczovL2lkZW50aXR5dG9vbGtpdC5nb29nbGVhcGlzLmNvbS9nb29nbGUuaWRlbnRpdHkuaWRlbnRpdHl0b29sa2l0LnYxLklkZW50aXR5VG9vbGtpdCIsImNsYWltcyI6eyJvd25lcklkIjoiVm9Ea05aIiwiYWRtaW4iOmZhbHNlfSwiZXhwIjoxNjk2Mzc0NTU0LCJpYXQiOjE2OTYzNzA5NTQsImlzcyI6ImZpcmViYXNlLWFkbWluc2RrLThva3lsQGNvZGVwZW4tc3RvcmUtcHJvZHVjdGlvbi5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInN1YiI6ImZpcmViYXNlLWFkbWluc2RrLThva3lsQGNvZGVwZW4tc3RvcmUtcHJvZHVjdGlvbi5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInVpZCI6IlZvRGtOWiJ9.rzuk4jKee8Ht8C9XI1AmsOhf9CzBKJN_hYjeQ2Mw9CxDIXc_g_k0_uAyL5cZp9qIRjLZ7k8GInntO9qSD4UahFVyVuZ_36mWaGoaSvmn20zG-ecbJUVGfa2qm7jbUrO4u2VivmkT_4au-aGp7QqlYmZo33C5KgMG0p6nidaR_Sb6CmvbJYXFuQMdvftPL3sjUpBDaJmtCRqZAuzYm1hklezIB75zR7y5QqVH8H9Ocmmyx0Kj4pJT5-RgX0_Ln0-vN6ZVARgLgiChEFeHLzGYleunedt-JaPjDs2g9op2XX5R0nRAK2tytZ9kxrta_O39UluX4y8C5AjjKt9GbF-rXQ"},"__pay_stripe_public_key":"pk_live_2GndomDfiklqpSNQn8FrGuwZSMIMzha7DkLJqlYe7IR0ihKAlKdiHg68JJc5eVPt68rzAjzAAVXcUwjySHRCsgjQQ00gtRBUFNH","__pay_braintree_env":"production","__item":"{\"id\":44397054,\"user_id\":219932,\"html\":\"<main id=\\\"wrapper\\\">\\n <header class=\\\"mobile\\\">\\n <h1><span>Happy<\\/span><\\/h1>\\n <h1><span>Birth<\\/span><\\/h1>\\n <h1><span>day<\\/span><\\/h1>\\n <h1><span>Anth<\\/span><\\/h1>\\n <h1><span>ony!<\\/span><\\/h1>\\n <\\/header>\\n <header class=\\\"desktop\\\">\\n <h1><span>Happy<\\/span><\\/h1>\\n <h1><span>Birthday<\\/span><\\/h1>\\n <h1><span>Anthony!<\\/span><\\/h1>\\n <\\/header> \\n<\\/main>\\n<canvas id=\\\"birthday\\\"><\\/canvas>\",\"css\":\"$blue1: midnightblue;\\n$blue2: darken(midnightblue,20%);\\n\\n@import url('https:\\/\\/fonts.googleapis.com\\/css2?family=Concert+One&display=swap');\\n\\nhtml, body {\\n height: 100%;\\n background: black;\\n}\\n\\nhtml {\\n box-sizing: border-box;\\n}\\n\\n*, *::before, *::after {\\n box-sizing: inherit;\\n &:focus {\\n outline: none;\\n }\\n}\\n\\n* {\\n font-family: monaco, courier;\\n}\\n\\nbody {\\n margin: 0;\\n padding: 0;\\n}\\n\\ncanvas {\\n display: block;\\n}\\n\\n#wrapper {\\n width: 100%;\\n height: 100%;\\n position: absolute;\\n top: 50%;\\n left: 50%;\\n transform: translate(-50%, -56%);\\n width: 100%;\\n display: flex;\\n flex-direction: column;\\n justify-content: center;\\n align-items: center;\\n overflow: hidden;\\n @media (min-width: 768px) {\\n transform: translate(-50%, -50%);\\n }\\n}\\n\\nheader {\\n &.mobile {\\n display: block;\\n @media (min-width: 768px) {\\n display: none;\\n }\\n h1, span {\\n font-size: 18vw;\\n @media (min-width: 480px) {\\n font-size: 24vw;\\n }\\n }\\n }\\n &.desktop {\\n display: none;\\n @media (min-width: 768px) {\\n display: block;\\n }\\n h1, span {\\n font-size: 14vw;\\n @media (min-width: 1200px) {\\n font-size: 16vw;\\n }\\n @media (min-width: 1600px) {\\n font-size: 18vw;\\n }\\n }\\n }\\n}\\n\\nh1,\\nspan {\\n margin: 0;\\n padding: 0;\\n font-family: 'Concert One', monaco, courier;\\n line-height: 0.8;\\n text-transform: uppercase;\\n letter-spacing: 3px;\\n text-align: center;\\n overflow: hidden;\\n color: WhiteSmoke;\\n span {\\n display: block;\\n transform: translate(0,100%);\\n animation: reveal 0.5s ease-out 0.25s forwards;\\n @media (max-width: 768px) {\\n line-height: 1.2;\\n }\\n }\\n}\\n\\n@for $i from 0 through 4 {\\n h1:nth-child(#{($i + 1)}) span {\\n animation-delay: #{$i * 0.25 + 2 }s;\\n }\\n}\\n\\n@keyframes reveal {\\n 0% {\\n transform: translate(0,100%);\\n }\\n 100% {\\n transform: translate(0,0);\\n }\\n}\",\"js\":\"\\/\\/ helper functions\\nconst PI2 = Math.PI * 2\\nconst random = (min, max) => Math.random() * (max - min + 1) + min | 0\\nconst timestamp = _ => new Date().getTime()\\n\\n\\/\\/ container\\nclass Birthday {\\n constructor() {\\n this.resize()\\n\\n \\/\\/ create a lovely place to store the firework\\n this.fireworks = []\\n this.counter = 0\\n\\n }\\n \\n resize() {\\n let body = document.body,\\n html = document.documentElement;\\n let docHeight = Math.max( body.scrollHeight, body.offsetHeight, \\n html.clientHeight, html.scrollHeight, html.offsetHeight );\\n this.width = canvas.width = window.innerWidth\\n let center = this.width \\/ 2 | 0\\n this.spawnA = center - center \\/ 4 | 0\\n this.spawnB = center + center \\/ 4 | 0\\n this.height = canvas.height = docHeight\\n this.spawnC = this.height * .1\\n this.spawnD = this.height * .5\\n }\\n \\n onClick(evt) {\\n let x = evt.clientX || evt.touches && evt.touches[0].pageX\\n let y = evt.clientY || evt.touches && evt.touches[0].pageY\\n let count = random(3,5)\\n for(let i = 0; i < count; i++) this.fireworks.push(new Firework(\\n random(this.spawnA, this.spawnB),\\n this.height,\\n x,\\n y,\\n random(0, 260),\\n random(30, 110)))\\n this.counter = -1\\n }\\n \\n update(delta) {\\n ctx.globalCompositeOperation = 'hard-light'\\n ctx.fillStyle = `rgba(20,20,20,${ 7 * delta })`\\n ctx.fillRect(0, 0, this.width, this.height)\\n ctx.globalCompositeOperation = 'lighter'\\n for (let firework of this.fireworks) firework.update(delta)\\n \\/\\/ if enough time passed... create new new firework\\n this.counter += delta * 3 \\/\\/ each second\\n if (this.counter >= 1) {\\n this.fireworks.push(new Firework(\\n random(this.spawnA, this.spawnB),\\n this.height,\\n random(0, this.width),\\n random(this.spawnC, this.spawnD),\\n random(0, 360),\\n random(30, 110)))\\n this.counter = 0\\n }\\n \\/\\/ remove the dead fireworks\\n if (this.fireworks.length > 1000) this.fireworks = this.fireworks.filter(firework => !firework.dead)\\n }\\n}\\n\\nclass Firework {\\n constructor(x, y, targetX, targetY, shade, offsprings) {\\n this.dead = false\\n this.offsprings = offsprings\\n this.x = x\\n this.y = y\\n this.targetX = targetX\\n this.targetY = targetY\\n this.shade = shade\\n this.history = []\\n }\\n update(delta) {\\n if (this.dead) return\\n let xDiff = this.targetX - this.x\\n let yDiff = this.targetY - this.y\\n \\n if (Math.abs(xDiff) > 3 || Math.abs(yDiff) > 3) { \\/\\/ is still moving\\n this.x += xDiff * 2 * delta\\n this.y += yDiff * 2 * delta\\n this.history.push({\\n x: this.x,\\n y: this.y\\n })\\n if (this.history.length > 20) this.history.shift()\\n } else {\\n if (this.offsprings && !this.madeChilds) {\\n let babies = this.offsprings \\/ 2\\n for (let i = 0; i < babies; i++) {\\n let targetX = this.x + this.offsprings * Math.cos(PI2 * i \\/ babies) | 0\\n let targetY = this.y + this.offsprings * Math.sin(PI2 * i \\/ babies) | 0\\n birthday.fireworks.push(new Firework(this.x, this.y, targetX, targetY, this.shade, 0))\\n }\\n }\\n this.madeChilds = true\\n this.history.shift()\\n }\\n \\n if (this.history.length === 0) this.dead = true\\n else if (this.offsprings) { \\n for (let i = 0; this.history.length > i; i++) {\\n let point = this.history[i]\\n ctx.beginPath()\\n ctx.fillStyle = 'hsl(' + this.shade + ',100%,' + i + '%)'\\n ctx.arc(point.x, point.y, 1, 0, PI2, false)\\n ctx.fill()\\n } \\n } else {\\n ctx.beginPath()\\n ctx.fillStyle = 'hsl(' + this.shade + ',100%,50%)'\\n ctx.arc(this.x, this.y, 1, 0, PI2, false)\\n ctx.fill()\\n }\\n\\n }\\n}\\n\\nlet canvas = document.getElementById('birthday')\\nlet ctx = canvas.getContext('2d')\\nlet then = timestamp()\\nlet birthday = new Birthday\\n\\nwindow.onresize = () => birthday.resize()\\ndocument.onclick = evt => birthday.onClick(evt)\\ndocument.ontouchstart = evt => birthday.onClick(evt)\\n\\n;(function loop(){\\n requestAnimationFrame(loop)\\n let now = timestamp()\\n let delta = now - then\\n then = now\\n birthday.update(delta \\/ 1000)\\n})()\\n\",\"html_pre_processor\":\"none\",\"css_pre_processor\":\"scss\",\"js_pre_processor\":\"none\",\"html_classes\":\"\",\"css_starter\":\"neither\",\"js_library\":null,\"created_at\":\"2020-04-29T17:07:05.000Z\",\"updated_at\":\"2020-10-20T15:48:30.000Z\",\"title\":\"Anthony's Birthday CodeCard 2020\",\"description\":\"\",\"slug_hash\":\"PoPKjab\",\"head\":\"\",\"private\":false,\"slug_hash_private\":\"1537e909c09362d8a89e7e53cadf8013\",\"has_animation\":true,\"team_id\":0,\"css_prefix\":\"neither\",\"template\":false,\"parent_id\":0,\"comments_count\":0,\"custom_screenshot_filename\":null,\"loves_count\":0,\"pick\":false,\"popularity_score\":0,\"views_count\":0,\"pick_visible_at\":null,\"cpid\":\"0171c6e7-fea8-7ee7-a29a-f89f2c2cd05a\",\"is_new_editor_pen\":false,\"pen_hash\":null,\"hashid\":\"PoPKjab\"}"}