luminomorphism
Version:
A UI design system built around light, blur, ambient motion and perceptual feedback.
41 lines (40 loc) • 2.42 kB
JavaScript
class LPrismLayer extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this.wrapper=document.createElement("div"),this.wrapper.classList.add("prism-layer"),this.wrapper.innerHTML="<slot></slot>",this.styleEl=document.createElement("style"),this.shadowRoot.append(this.styleEl,this.wrapper),this.intensity=this.getAttribute("intensity")||"medium",this.interaction=this.getAttribute("interaction")||"hover",this.mouse={x:0,y:0},this.animate=this.animate.bind(this)}connectedCallback(){this.updateStyle(),this.interaction==="cursor"&&this.addEventListener("pointermove",this.trackMouse.bind(this)),requestAnimationFrame(this.animate)}static get observedAttributes(){return["intensity","interaction"]}attributeChangedCallback(e,t,i){t!==i&&(this[e]=i,this.updateStyle())}trackMouse(e){const t=this.getBoundingClientRect();this.mouse.x=e.clientX-t.left,this.mouse.y=e.clientY-t.top}animate(){const e=this.wrapper;if(this.interaction==="cursor"){const t=this.mouse.x,i=this.mouse.y,s=this.offsetWidth/2,r=this.offsetHeight/2,n=t-s,o=i-r,a=Math.atan2(o,n)*(180/Math.PI);e.style.setProperty("--prism-angle",`${a}deg`)}requestAnimationFrame(this.animate)}updateStyle(){const t={low:"0.15",medium:"0.3",high:"0.5"}[this.intensity]||"0.3",i={hover:`
.prism-layer::before {
opacity: 0;
transform: rotate(0deg);
}
.prism-layer:hover::before {
opacity: ${t};
transform: rotate(25deg);
}
`,always:`
.prism-layer::before {
opacity: ${t};
transform: rotate(0deg);
}
`,cursor:`
.prism-layer::before {
opacity: ${t};
transform: rotate(var(--prism-angle, 0deg));
}
`},s=i[this.interaction]||i.hover;this.styleEl.textContent=`
.prism-layer {
position: relative;
display: inline-block;
overflow: hidden;
background: inherit;
border-radius: 12px;
}
.prism-layer::before {
content: "";
position: absolute;
inset: 0;
background: conic-gradient(from 0deg, red, orange, yellow, green, blue, indigo, violet, red);
mix-blend-mode: screen;
filter: blur(20px) hue-rotate(0deg);
pointer-events: none;
transition: opacity 0.4s ease, transform 0.4s ease;
z-index: 1;
}
${s}
`}}customElements.define("l-prism-layer",LPrismLayer);