Standard
$29/mo
- Core features
- Email support
- Single workspace
Components and Effects I have used in other projects.
Diffent background styles you can use. Without layering over HTML.
<div class="particles-section">
<div class="particles-field">
<div class="particles-layer particles-layer--1"></div>
<div class="particles-layer particles-layer--2"></div>
<div class="particles-layer particles-layer--3"></div>
</div>
</div>
.particles-section {
position: relative;
min-height: 320px;
display: flex;
align-items: center;
justify-content: center;
background: radial-gradient(circle at top, #020617 0, #000 65%);
overflow: hidden;
}
.particles-field {
position: relative;
width: 100%;
max-width: 900px;
aspect-ratio: 16 / 9;
border-radius: 1.2rem;
overflow: hidden;
border: 1px solid rgba(148, 163, 184, 0.35);
background: radial-gradient(circle at top, #020617 0, #000 70%);
}
/* Shared layer styles */
.particles-layer {
position: absolute;
inset: -10%;
background-repeat: repeat;
mix-blend-mode: screen;
opacity: 0.7;
}
/* Fine grain */
.particles-layer--1 {
background-image:
radial-gradient(circle, rgba(148, 163, 184, 0.6) 1px, transparent 55%);
background-size: 40px 40px;
animation: particles-drift-1 42s linear infinite;
}
/* Medium blobs */
.particles-layer--2 {
background-image:
radial-gradient(circle, rgba(56, 189, 248, 0.55) 2px, transparent 60%);
background-size: 80px 80px;
animation: particles-drift-2 55s linear infinite;
}
/* Larger soft lights */
.particles-layer--3 {
background-image:
radial-gradient(circle, rgba(34, 197, 94, 0.35) 8px, transparent 70%);
background-size: 180px 180px;
animation: particles-drift-3 75s linear infinite;
}
@keyframes particles-drift-1 {
0% { transform: translate3d(0, 0, 0); }
100% { transform: translate3d(60px, -80px, 0); }
}
@keyframes particles-drift-2 {
0% { transform: translate3d(0, 0, 0); }
100% { transform: translate3d(-90px, 60px, 0); }
}
@keyframes particles-drift-3 {
0% { transform: translate3d(0, 0, 0); }
100% { transform: translate3d(40px, 90px, 0); }
}
// JS-driven dots (example)
const container = document.querySelector('.particles-field');
const DOT_COUNT = 40;
for (let i = 0; i < DOT_COUNT; i++) {
const dot = document.createElement('span');
dot.className = 'particles-dot';
container.appendChild(dot);
}
Moving rainbow stripes that can be applied to a Hero Section with no JS.
<section class="demo-stripes">
<div class="demo-stripes__hero"></div>
<div class="demo-stripes__content">
<h3 class="demo-stripes__heading" data-text="An awesome title">
An awesome title
</h3>
<input type="checkbox" id="demo-stripes-switch" class="demo-stripes__switch" />
<label for="demo-stripes-switch" class="demo-stripes__toggle">
<span>
<span class="demo-stripes__icon">→</span>
switch bg
</span>
</label>
</div>
</section>
/* Scoped Houdini stripes hero */
@property --blink-opacity {
syntax: "<number>";
inherits: false;
initial-value: 1;
}
@keyframes demo-stripes-blink {
0%, 100% { opacity: var(--blink-opacity, 1); }
50% { opacity: 0; }
}
@keyframes demo-stripes-bg-pan {
from { background-position: 50% 50%, 50% 50%; }
to { background-position: 350% 50%, 350% 50%; }
}
/* Root of the card demo */
.demo-stripes {
position: relative;
width: 100%;
height: 100%;
min-height: 240px;
border-radius: 1rem;
overflow: hidden;
--stripe-color: #fff;
--bg: var(--stripe-color);
}
/* Background rainbow + stripes */
.demo-stripes__hero {
width: 100%;
height: 100%;
position: relative;
display: flex;
place-content: center;
place-items: center;
--stripes: repeating-linear-gradient(
100deg,
var(--stripe-color) 0%,
var(--stripe-color) 7%,
transparent 10%,
transparent 12%,
var(--stripe-color) 16%
);
--rainbow: repeating-linear-gradient(
100deg,
#60a5fa 10%,
#e879f9 15%,
#60a5fa 20%,
#5eead4 25%,
#60a5fa 30%
);
background-image: var(--stripes), var(--rainbow);
background-size: 300%, 200%;
background-position: 50% 50%, 50% 50%;
filter: blur(10px) invert(100%);
mask-image: radial-gradient(ellipse at 100% 0%, black 40%, transparent 70%);
-webkit-mask-image: radial-gradient(ellipse at 100% 0%, black 40%, transparent 70%);
}
.demo-stripes__hero::after {
content: "";
position: absolute;
inset: 0;
background-image: var(--stripes), var(--rainbow);
background-size: 200%, 100%;
animation: demo-stripes-bg-pan 60s linear infinite;
mix-blend-mode: difference;
}
/* Toggle theme when checked */
.demo-stripes:has(.demo-stripes__switch:checked) {
--stripe-color: #000;
}
.demo-stripes:has(.demo-stripes__switch:checked) .demo-stripes__hero,
.demo-stripes:has(.demo-stripes__switch:checked) .demo-stripes__hero::after {
filter: blur(10px) opacity(0.5) saturate(2);
}
/* Foreground content */
.demo-stripes__content {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
gap: 1.4rem;
align-items: center;
justify-content: center;
text-align: center;
mix-blend-mode: difference;
-webkit-mix-blend-mode: difference;
filter: invert(1);
padding: 1.5rem;
}
/* Heading glass effect */
.demo-stripes__heading {
position: relative;
margin: 0;
font-size: clamp(1.4rem, 1rem + 3vw, 2.4rem);
}
.demo-stripes__heading::before {
content: attr(data-text);
position: absolute;
inset: 0;
background: white;
text-shadow: 0 0 1px #ffffff;
background-clip: text;
-webkit-text-fill-color: transparent;
-webkit-mask: linear-gradient(#000 0 0) luminance;
mask: linear-gradient(#000 0 0) luminance, alpha;
backdrop-filter: blur(19px) brightness(12.5);
-webkit-text-stroke: 1px white;
display: flex;
align-items: center;
justify-content: center;
pointer-events: none;
}
/* Switch */
.demo-stripes__switch {
appearance: none;
-webkit-appearance: none;
opacity: 0;
position: absolute;
}
.demo-stripes__toggle {
cursor: pointer;
padding: 0.5rem 0.75rem;
border-radius: 999px;
border: 1px solid rgba(148, 163, 184, 0.6);
background: rgba(15, 23, 42, 0.9);
color: #e5e7eb;
display: inline-flex;
align-items: center;
gap: 0.5rem;
font-size: 0.85rem;
transition: 0.3s ease;
}
.demo-stripes__toggle:hover,
.demo-stripes__toggle:active,
.demo-stripes__toggle:focus-within {
animation: demo-stripes-switch 0.2s alternate;
}
@keyframes demo-stripes-switch {
50% {
transform: scale(1.2);
font-weight: 900;
}
}
/* Blinking icon */
.demo-stripes__icon {
width: 1lh;
height: 1lh;
aspect-ratio: 1 / 1;
padding: 0.25em 0.35rem;
border-radius: 999px;
border: 1px dashed currentColor;
--blink-opacity: 1;
animation: demo-stripes-blink 2s ease-in-out infinite running;
}
// No JS required for the demo:
// background switch is driven by :has() and a checkbox.
// (You can enhance it later if you want.)
Perfect for comparing subscription tiers, and product differences.
<section class="pricing-row">
<article class="pricing-card pricing-card--standard">
<h3 class="pricing-card__title">Standard</h3>
<div class="pricing-card__price">
$29<span class="pricing-card__price-suffix">/mo</span>
</div>
<ul class="pricing-card__features">
<li>Core features</li>
<li>Email support</li>
<li>Single workspace</li>
</ul>
</article>
<article class="pricing-card pricing-card--pro">
<h3 class="pricing-card__title">Pro</h3>
<div class="pricing-card__price">
$59<span class="pricing-card__price-suffix">/mo</span>
</div>
<ul class="pricing-card__features">
<li>Everything in Standard</li>
<li>Priority support</li>
<li>Team workspaces</li>
</ul>
</article>
</section>
.pricing-row {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 1.7rem;
}
.pricing-card {
position: relative;
width: min(260px, 100%);
padding: 1.6rem 1.4rem;
border-radius: 1.1rem;
border: 1px solid rgba(148, 163, 184, 0.4);
background: radial-gradient(circle at top, #020617 0, #020617 45%, #000 100%);
box-shadow: 0 18px 40px rgba(15, 23, 42, 0.65);
overflow: hidden;
cursor: pointer;
transition:
transform 0.25s ease,
box-shadow 0.25s ease,
border-color 0.25s ease,
filter 0.25s ease;
}
.pricing-card--standard { --pricing-accent: #38bdf8; }
.pricing-card--pro { --pricing-accent: #22c55e; }
/* Radial spotlight glow */
.pricing-card::before {
content: "";
position: absolute;
inset: -40%;
background: radial-gradient(
circle at var(--spot-x, 50%) var(--spot-y, 0%),
color-mix(in oklab, var(--pricing-accent) 65%, transparent 35%) 0,
transparent 65%
);
opacity: 0;
transition: opacity 0.25s ease;
z-index: 0;
}
.pricing-card::after {
content: "";
position: absolute;
inset: 1px;
border-radius: inherit;
background: linear-gradient(to bottom,
rgba(15, 23, 42, 0.9),
rgba(15, 23, 42, 0.96)
);
z-index: 0;
}
.pricing-card__title,
.pricing-card__price,
.pricing-card__features {
position: relative;
z-index: 1;
}
/* ...other text styles omitted for brevity... */
/* Spotlight behaviour */
.pricing-row:hover .pricing-card {
filter: brightness(0.45) saturate(0.9);
}
.pricing-card:hover,
.pricing-card:focus-within {
transform: translateY(-8px);
box-shadow: 0 22px 55px rgba(15, 23, 42, 0.85);
border-color: color-mix(in oklab, var(--pricing-accent) 65%, #1e293b 35%);
filter: none;
}
.pricing-card:hover::before,
.pricing-card:focus-within::before {
opacity: 0.9;
}
// Mouse-follow spotlight (per card)
const cards = document.querySelectorAll('.pricing-card');
cards.forEach(card => {
card.addEventListener('mousemove', e => {
const r = card.getBoundingClientRect();
const x = ((e.clientX - r.left) / r.width) * 100;
const y = ((e.clientY - r.top) / r.height) * 100;
card.style.setProperty('--spot-x', x.toFixed(1) + '%');
card.style.setProperty('--spot-y', y.toFixed(1) + '%');
});
card.addEventListener('mouseleave', () => {
card.style.removeProperty('--spot-x');
card.style.removeProperty('--spot-y');
});
});
A call-to-action button that flips on hover.
<div class="cta-wrapper">
<a href="#" class="cta-button-3d">
<span>Let's Begin</span>
<span>Let's Begin</span>
<span>Let's Begin</span>
<span>Let's Begin</span>
</a>
</div>
.cta-wrapper {
display: flex;
align-items: center;
justify-content: center;
}
.cta-button-3d {
position: relative;
width: 170px;
height: 54px;
display: inline-block;
transform-style: preserve-3d;
transform: perspective(1000px) rotateX(0deg);
transition: transform 4s;
text-decoration: none;
}
.cta-button-3d:hover {
transform: perspective(1000px) rotateX(360deg);
}
.cta-button-3d span {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
sans-serif;
text-transform: uppercase;
letter-spacing: 0.16em;
font-size: 0.8rem;
background: rgba(255, 255, 255, 0.92);
color: #020617;
border-radius: 999px;
border: 2px solid #000;
box-sizing: border-box;
box-shadow:
inset 0 18px 40px rgba(255, 255, 255, 0.9),
0 10px 30px rgba(0, 0, 0, 0.7);
transition:
background-color 0.4s ease,
color 0.4s ease,
box-shadow 0.4s ease;
}
.cta-button-3d:hover span {
background: linear-gradient(135deg, #0ea5e9, #22c55e);
color: #f9fafb;
box-shadow:
inset 0 0 0 rgba(0, 0, 0, 0),
0 14px 40px rgba(8, 47, 73, 0.9);
}
/* Each side of the "cube" */
.cta-button-3d span:nth-child(1) {
transform: rotateX(0deg) translateZ(27px);
}
.cta-button-3d span:nth-child(2) {
transform: rotateX(90deg) translateZ(27px);
}
.cta-button-3d span:nth-child(3) {
transform: rotateX(180deg) translateZ(27px);
}
.cta-button-3d span:nth-child(4) {
transform: rotateX(270deg) translateZ(27px);
}
// Optional enhancements:
// - Trigger rotation on click instead of hover
// - Tie animation to scroll or section visibility.