Created
December 24, 2024 05:28
-
-
Save djsnipa1/f7d61a98071f1b30c559aebdf17e9367 to your computer and use it in GitHub Desktop.
Revisions
-
djsnipa1 created this gist
Dec 24, 2024 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,33 @@ <main> <div class="card"> <pixel-canvas></pixel-canvas> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentcolor" viewBox="0 0 256 256"> <path d="M216,42H40A14,14,0,0,0,26,56V200a14,14,0,0,0,14,14H216a14,14,0,0,0,14-14V56A14,14,0,0,0,216,42ZM40,54H216a2,2,0,0,1,2,2V98H38V56A2,2,0,0,1,40,54ZM38,200V110H98v92H40A2,2,0,0,1,38,200Zm178,2H110V110H218v90A2,2,0,0,1,216,202Z"></path> </svg> <button>Layout</buton> </div> <div class="card" style="--active-color: #e0f2fe"> <pixel-canvas data-gap="10" data-speed="25" data-colors="#e0f2fe, #7dd3fc, #0ea5e9"></pixel-canvas> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentcolor" viewBox="0 0 256 256"> <path d="M67.84,92.61,25.37,128l42.47,35.39a6,6,0,1,1-7.68,9.22l-48-40a6,6,0,0,1,0-9.22l48-40a6,6,0,0,1,7.68,9.22Zm176,30.78-48-40a6,6,0,1,0-7.68,9.22L230.63,128l-42.47,35.39a6,6,0,1,0,7.68,9.22l48-40a6,6,0,0,0,0-9.22Zm-81.79-89A6,6,0,0,0,154.36,38l-64,176A6,6,0,0,0,94,221.64a6.15,6.15,0,0,0,2,.36,6,6,0,0,0,5.64-3.95l64-176A6,6,0,0,0,162.05,34.36Z"></path> </svg> <button>Code</buton> </div> <div class="card" style="--active-color: #fef08a"> <pixel-canvas data-gap="3" data-speed="20" data-colors="#fef08a, #fde047, #eab308"></pixel-canvas> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentcolor" viewBox="0 0 256 256"> <path d="M180,146H158V110h22a34,34,0,1,0-34-34V98H110V76a34,34,0,1,0-34,34H98v36H76a34,34,0,1,0,34,34V158h36v22a34,34,0,1,0,34-34ZM158,76a22,22,0,1,1,22,22H158ZM54,76a22,22,0,0,1,44,0V98H76A22,22,0,0,1,54,76ZM98,180a22,22,0,1,1-22-22H98Zm12-70h36v36H110Zm70,92a22,22,0,0,1-22-22V158h22a22,22,0,0,1,0,44Z"></path> </svg> <button>Command</buton> </div> <div class="card" style="--active-color: #fecdd3"> <pixel-canvas data-gap="6" data-speed="80" data-colors="#fecdd3, #fda4af, #e11d48" data-no-focus></pixel-canvas> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentcolor" viewBox="0 0 256 256"> <path d="M222,67.34a33.81,33.81,0,0,0-10.64-24.25C198.12,30.56,176.68,31,163.54,44.18L142.82,65l-.63-.63a22,22,0,0,0-31.11,0l-9,9a14,14,0,0,0,0,19.81l3.47,3.47L53.14,149.1a37.81,37.81,0,0,0-9.84,36.73l-8.31,19a11.68,11.68,0,0,0,2.46,13A13.91,13.91,0,0,0,47.32,222,14.15,14.15,0,0,0,53,220.82L71,212.92a37.92,37.92,0,0,0,35.84-10.07l52.44-52.46,3.47,3.48a14,14,0,0,0,19.8,0l9-9a22.06,22.06,0,0,0,0-31.13l-.66-.65L212,91.85A33.76,33.76,0,0,0,222,67.34Zm-123.61,127a26,26,0,0,1-26,6.47,6,6,0,0,0-4.17.24l-20,8.75a2,2,0,0,1-2.09-.31l9.12-20.9a5.94,5.94,0,0,0,.19-4.31A25.91,25.91,0,0,1,56,166h70.78ZM138.78,154H65.24l48.83-48.84,36.76,36.78Zm64.77-70.59L178.17,108.9a6,6,0,0,0,0,8.47l4.88,4.89a10,10,0,0,1,0,14.15l-9,9a2,2,0,0,1-2.82,0l-60.69-60.7a2,2,0,0,1,0-2.83l9-9a10,10,0,0,1,14.14,0l4.89,4.89a6,6,0,0,0,4.24,1.75h0a6,6,0,0,0,4.25-1.77L172,52.66c8.57-8.58,22.51-9,31.07-.85a22,22,0,0,1,.44,31.57Z"></path> </svg> <button>Dropper</buton> </div> </main> This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,9 @@ <pixel-canvas> Web Component ---------------------------- Web Component that applies a shimmering pixel background on element hover. <a href="https://ryanmulligan.dev/blog/pixel-canvas/">Read the blog post</a> A [Pen](https://codepen.io/hexagoncircle/pen/KwPpdBZ) by [Ryan Mulligan](https://codepen.io/hexagoncircle) on [CodePen](https://codepen.io). [License](https://codepen.io/license/pen/KwPpdBZ). This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,274 @@ class Pixel { constructor(canvas, context, x, y, color, speed, delay) { this.width = canvas.width; this.height = canvas.height; this.ctx = context; this.x = x; this.y = y; this.color = color; this.speed = this.getRandomValue(0.1, 0.9) * speed; this.size = 0; this.sizeStep = Math.random() * 0.4; this.minSize = 0.5; this.maxSizeInteger = 2; this.maxSize = this.getRandomValue(this.minSize, this.maxSizeInteger); this.delay = delay; this.counter = 0; this.counterStep = Math.random() * 4 + (this.width + this.height) * 0.01; this.isIdle = false; this.isReverse = false; this.isShimmer = false; } getRandomValue(min, max) { return Math.random() * (max - min) + min; } draw() { const centerOffset = this.maxSizeInteger * 0.5 - this.size * 0.5; this.ctx.fillStyle = this.color; this.ctx.fillRect( this.x + centerOffset, this.y + centerOffset, this.size, this.size ); } appear() { this.isIdle = false; if (this.counter <= this.delay) { this.counter += this.counterStep; return; } if (this.size >= this.maxSize) { this.isShimmer = true; } if (this.isShimmer) { this.shimmer(); } else { this.size += this.sizeStep; } this.draw(); } disappear() { this.isShimmer = false; this.counter = 0; if (this.size <= 0) { this.isIdle = true; return; } else { this.size -= 0.1; } this.draw(); } shimmer() { if (this.size >= this.maxSize) { this.isReverse = true; } else if (this.size <= this.minSize) { this.isReverse = false; } if (this.isReverse) { this.size -= this.speed; } else { this.size += this.speed; } } } class PixelCanvas extends HTMLElement { static register(tag = "pixel-canvas") { if ("customElements" in window) { customElements.define(tag, this); } } static css = ` :host { display: grid; inline-size: 100%; block-size: 100%; overflow: hidden; } `; get colors() { return this.dataset.colors?.split(",") || ["#f8fafc", "#f1f5f9", "#cbd5e1"]; } get gap() { const value = this.dataset.gap || 5; const min = 4; const max = 50; if (value <= min) { return min; } else if (value >= max) { return max; } else { return parseInt(value); } } get speed() { const value = this.dataset.speed || 35; const min = 0; const max = 100; const throttle = 0.001; if (value <= min || this.reducedMotion) { return min; } else if (value >= max) { return max * throttle; } else { return parseInt(value) * throttle; } } get noFocus() { return this.hasAttribute("data-no-focus"); } connectedCallback() { const canvas = document.createElement("canvas"); const sheet = new CSSStyleSheet(); this._parent = this.parentNode; this.shadowroot = this.attachShadow({ mode: "open" }); sheet.replaceSync(PixelCanvas.css); this.shadowroot.adoptedStyleSheets = [sheet]; this.shadowroot.append(canvas); this.canvas = this.shadowroot.querySelector("canvas"); this.ctx = this.canvas.getContext("2d"); this.timeInterval = 1000 / 60; this.timePrevious = performance.now(); this.reducedMotion = window.matchMedia( "(prefers-reduced-motion: reduce)" ).matches; this.init(); this.resizeObserver = new ResizeObserver(() => this.init()); this.resizeObserver.observe(this); this._parent.addEventListener("mouseenter", this); this._parent.addEventListener("mouseleave", this); if (!this.noFocus) { this._parent.addEventListener("focusin", this); this._parent.addEventListener("focusout", this); } } disconnectedCallback() { this.resizeObserver.disconnect(); this._parent.removeEventListener("mouseenter", this); this._parent.removeEventListener("mouseleave", this); if (!this.noFocus) { this._parent.removeEventListener("focusin", this); this._parent.removeEventListener("focusout", this); } delete this._parent; } handleEvent(event) { this[`on${event.type}`](event); } onmouseenter() { this.handleAnimation("appear"); } onmouseleave() { this.handleAnimation("disappear"); } onfocusin(e) { if (e.currentTarget.contains(e.relatedTarget)) return; this.handleAnimation("appear"); } onfocusout(e) { if (e.currentTarget.contains(e.relatedTarget)) return; this.handleAnimation("disappear"); } handleAnimation(name) { cancelAnimationFrame(this.animation); this.animation = this.animate(name); } init() { const rect = this.getBoundingClientRect(); const width = Math.floor(rect.width); const height = Math.floor(rect.height); this.pixels = []; this.canvas.width = width; this.canvas.height = height; this.canvas.style.width = `${width}px`; this.canvas.style.height = `${height}px`; this.createPixels(); } getDistanceToCanvasCenter(x, y) { const dx = x - this.canvas.width / 2; const dy = y - this.canvas.height / 2; const distance = Math.sqrt(dx * dx + dy * dy); return distance; } createPixels() { for (let x = 0; x < this.canvas.width; x += this.gap) { for (let y = 0; y < this.canvas.height; y += this.gap) { const color = this.colors[ Math.floor(Math.random() * this.colors.length) ]; const delay = this.reducedMotion ? 0 : this.getDistanceToCanvasCenter(x, y); this.pixels.push( new Pixel(this.canvas, this.ctx, x, y, color, this.speed, delay) ); } } } animate(fnName) { this.animation = requestAnimationFrame(() => this.animate(fnName)); const timeNow = performance.now(); const timePassed = timeNow - this.timePrevious; if (timePassed < this.timeInterval) return; this.timePrevious = timeNow - (timePassed % this.timeInterval); this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); for (let i = 0; i < this.pixels.length; i++) { this.pixels[i][fnName](); } if (this.pixels.every((pixel) => pixel.isIdle)) { cancelAnimationFrame(this.animation); } } } PixelCanvas.register(); This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,125 @@ :root { --space: 1rem; --bg: #09090b; --fg: #e3e3e3; --surface-1: #101012; --surface-2: #27272a; --surface-3: #52525b; --ease-out: cubic-bezier(0.5, 1, 0.89, 1); --ease-in-out: cubic-bezier(0.45, 0, 0.55, 1); } * { box-sizing: border-box; } height, body { height: 100%; } body { display: grid; color: var(--fg); background: var(--bg); padding: var(--space); min-height: 100vh; } main { display: grid; grid-template-columns: repeat(var(--count, 1), 1fr); gap: var(--space); margin: auto; inline-size: min(var(--max, 15rem), 100%); @media (min-width: 25rem) { --count: 2; --max: 30rem; } @media (min-width: 45rem) { --count: 4; --max: 60rem; } } .card { position: relative; overflow: hidden; display: grid; grid-template-areas: "card"; place-items: center; aspect-ratio: 4/5; border: 1px solid var(--surface-2); isolation: isolate; transition: border-color 200ms var(--ease-out); user-select: none; &::before { content: ""; position: absolute; inset: 0; background: radial-gradient( circle at bottom left, transparent 55%, var(--surface-1) ); pointer-events: none; box-shadow: var(--bg) -0.5cqi 0.5cqi 2.5cqi inset; transition: opacity 900ms var(--ease-out); } &::after { content: ""; position: absolute; inset: 0; margin: auto; aspect-ratio: 1; background: radial-gradient(circle, var(--bg), transparent 65%); opacity: 0; transition: opacity 800ms var(--ease-out); } > * { grid-area: card; } svg { position: relative; z-index: 1; width: 30%; height: auto; color: var(--surface-3); transition: 300ms var(--ease-out); transition-property: color, scale; } button { opacity: 0; } &:focus-within { outline: 5px auto Highlight; outline: 5px auto -webkit-focus-ring-color; } &:where(:hover, :focus-within) { border-color: var(--active-color, var(--fg)); transition: border-color 800ms var(--ease-in-out); } &:where(:hover, :focus-within) svg { color: var(--active-color, var(--fg)); scale: 1.1; transition: 300ms var(--ease-in-out); } &:where(:hover, :focus-within)::before { opacity: 0; } &:where(:hover, :focus-within)::after { opacity: 1; } }