Fluted Glass
Installation
npm i @paper-design/shaders-react
Code
import { FlutedGlass } from '@paper-design/shaders-react'; <FlutedGlass colorShadow="#92aae3" size={0.85} shadows={0.4} highlights={0} distortion={0.15} edges={0} marginRight={0.1} marginTop={0.1} marginBottom={0.5} > <div className="demo"> <style>{`.demo { position: relative; height: 100%; color: #fff; overflow: hidden; timeline-scope: --demo-scroll } .demo .bg { position: absolute; top: 0; left: 0; right: 0; height: 300%; background: url(/images/html-in-canvas/succulents.jpg) center top / cover; filter: brightness(0.7); animation: bg-pan linear both; animation-timeline: --demo-scroll; animation-range: 0px 4000px } .demo ::selection { background: #ffd60a; color: #1a1a1a } .demo .scroller { height: 100%; overflow-y: auto; scrollbar-width: none; scroll-timeline: --demo-scroll; position: relative } .demo .scroller::after { content: ""; display: block; height: 60% } .demo article { position: relative; text-transform: uppercase; max-width: 1400px; padding: 180px 8% 0; font-family: system-ui, sans-serif; } .demo h1 { margin: 0; font-weight: bold; opacity: .8; line-height: .85; font-size: 180px; letter-spacing: -0.03em } .demo p { max-width: 80%; margin: 4% 0; font-size: 44px; } .demo .shapes { display: flex; flex-wrap: wrap; gap: 12px; margin: -2% 0 20% } .demo .shapes button { padding: 0.35em 0.9em; border: 2px solid rgb(255 255 255 / 50%); border-radius: 999px; background: none; color: inherit; font: inherit; font-size: 30px; text-transform: inherit; cursor: pointer } .demo .shapes button:hover { border-color: #fff } .demo .shapes button[aria-pressed="true"] { border-color: #ffd60a; background: #ffd60a; color: #1a1a1a } .demo kbd { padding: 0.05em 0.35em; border: 2px solid rgb(255 255 255 / 60%); border-bottom-width: 4px; border-radius: 0.25em; font: inherit; font-size: 0.85em } .demo .hint { position: fixed; bottom: 15px; right: 20px; display: flex; align-items: center; font-size: 22px; animation: hint-fade linear both; animation-timeline: --demo-scroll; animation-range: 0 16px } .demo .hint span { display: inline-block; padding-left: 0.5em; animation: hint-bounce 1.2s ease-in-out infinite } @keyframes bg-pan { to { transform: translateY(-2000px) } } @keyframes hint-fade { to { opacity: 0 } } @keyframes hint-bounce { 50% { transform: translateY(8px) } }`}</style> <div className="bg" /> <div className="scroller"> <article> <h1>Fluted glass</h1> <span className="hint"> scroll down <span>↓</span> </span> <p>Everything here is live HTML, drawn into a canvas and pushed through a fluted glass shader.</p> <p>Pick a shape for the flutes and watch the text bend differently:</p> <div className="shapes"> <button value="prism" aria-pressed onClick={(event) => setDistortionShape(event.currentTarget.value)}>prism</button> <button value="lens" aria-pressed={false} onClick={(event) => setDistortionShape(event.currentTarget.value)}>lens</button> <button value="contour" aria-pressed={false} onClick={(event) => setDistortionShape(event.currentTarget.value)}>contour</button> <button value="cascade" aria-pressed={false} onClick={(event) => setDistortionShape(event.currentTarget.value)}>cascade</button> <button value="flat" aria-pressed={false} onClick={(event) => setDistortionShape(event.currentTarget.value)}>flat</button> </div> <p>The photo behind scrolls at half speed with plain CSS, and the glass bends it just like the text.</p> <p> It is still real text: press <kbd>⌘+F</kbd> or <kbd>Ctrl+F</kbd> to find a word on the page, or drag across it to select. </p> <p>Forms, links and inputs keep working under the glass.</p> </article> </div> </div> </FlutedGlass>
Shader Props
Common Props
Description
Fluted glass image filter transforms an image into streaked, ribbed distortions, giving a mix of clarity and obscurity.