Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eleventy.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ module.exports = function(eleventyConfig) {
eleventyConfig.addPassthroughCopy("src/events/hm25-invite.ics");
eleventyConfig.addPassthroughCopy("src/webinars/2025/simplifying-opc-ua/opc-ua-webinar-flows.zip");
eleventyConfig.addPassthroughCopy("src/js/ai-expert-modal.js");
eleventyConfig.addPassthroughCopy("src/js/bending-grid.js");

// Watch content images for the image pipeline
eleventyConfig.addWatchTarget("src/**/*.{svg,webp,png,jpeg,gif}");
Expand Down
4 changes: 4 additions & 0 deletions src/_includes/layouts/base.njk
Original file line number Diff line number Diff line change
Expand Up @@ -546,4 +546,8 @@ eleventyComputed:
});
</script>
{%- endif -%}

<!-- Bending Grid Animation (homepage only) -->
<script src="/js/bending-grid.js" defer></script>

</html>
111 changes: 89 additions & 22 deletions src/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -1981,36 +1981,103 @@ lite-youtube::before {
}

.raster-gradient-bg {
background: radial-gradient(circle 80vw at 100% 0%, theme(colors.indigo.50), transparent);
position: relative;
min-height: 100vh;
}

.raster-gradient-bg::before {
content: "";
/* Grid Container - Extends beyond hero with bottom fade */
.bending-grid-container {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image:
linear-gradient(rgba(99, 102, 241, 0.15) 1px, transparent 1px),
linear-gradient(90deg, rgba(99, 102, 241, 0.15) 1px, transparent 1px);
width: 100%;
height: 120%; /* Extends 20% beyond hero */
pointer-events: none;
z-index: 1;
perspective: 1540px;
perspective-origin: 60% 25%;
/* Fade out at bottom - starts at 70%, transparent at 100% */
mask-image: linear-gradient(
to bottom,
black 0%,
black 70%,
rgba(0, 0, 0, 0.8) 80%,
rgba(0, 0, 0, 0.5) 90%,
transparent 100%
);
-webkit-mask-image: linear-gradient(
to bottom,
black 0%,
black 70%,
rgba(0, 0, 0, 0.8) 80%,
rgba(0, 0, 0, 0.5) 90%,
transparent 100%
);
}

/* Grid - Position adjusted for 120% container, with top fade */
.bending-grid {
position: absolute;
width: 250%;
height: 800%;
left: -75%;
top: 25%; /* Positioned just below AI text input */
background-image:
linear-gradient(rgba(99, 102, 241, 0.25) 1px, transparent 1px),
linear-gradient(90deg, rgba(99, 102, 241, 0.25) 1px, transparent 1px);
background-size: 20px 20px;

/* Mask using the gradient - grid fades in/out */
mask: linear-gradient(to top,
transparent 35%, /* invisible at bottom */
black 56%, /* fully visible starts */
black 78%, /* fully visible ends */
transparent 97% /* invisible at top */
transform-origin: center top;
/* Fade out top edge of grid pattern */
mask-image: linear-gradient(
to bottom,
transparent 0%,
rgba(0, 0, 0, 0.1) 1%,
rgba(0, 0, 0, 0.3) 2%,
rgba(0, 0, 0, 0.6) 3%,
rgba(0, 0, 0, 0.9) 4%,
black 5%
);
-webkit-mask: linear-gradient(to top,
transparent 35%,
black 56%,
black 78%,
transparent 97%
-webkit-mask-image: linear-gradient(
to bottom,
transparent 0%,
rgba(0, 0, 0, 0.1) 1%,
rgba(0, 0, 0, 0.3) 2%,
rgba(0, 0, 0, 0.6) 3%,
rgba(0, 0, 0, 0.9) 4%,
black 5%
);
}

/* Top fade - Absolute positioning within hero */
.grid-fade-top {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 70%;
background: linear-gradient(
to bottom,
white 0%,
white 20%,
rgba(255, 255, 255, 0.98) 40%,
rgba(255, 255, 255, 0.92) 55%,
rgba(255, 255, 255, 0.8) 70%,
rgba(255, 255, 255, 0.5) 85%,
transparent 100%
);

pointer-events: none;
border-radius: inherit;
z-index: 2;
}

/* Side fades - Absolute positioning within hero */
.grid-fade-sides {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background:
linear-gradient(to right, white 0%, transparent 20%, transparent 80%, white 100%);
pointer-events: none;
z-index: 2;
}
12 changes: 9 additions & 3 deletions src/index.njk
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ hubspot:
---
<!--Hero Content-->
<div class="w-full px-6 raster-gradient-bg">
<!-- Bending Grid Background (hero section only) -->
<div class="bending-grid-container" id="hero-grid-container">
<div class="bending-grid" id="hero-grid"></div>
<div class="grid-fade-top" id="grid-fade-top"></div>
<div class="grid-fade-sides"></div>
</div>
<div class="sm:max-w-screen-lg mt-6 sm:mt-12 mx-auto">
<div class="container m-auto text-left max-w-screen-lg">
<div class="mx-auto">
Expand All @@ -63,7 +69,7 @@ hubspot:
<p class="mt-6 sm:mt-10 text-center text-gray-600 md:text-xl max-w-4xl m-auto">
{{ site.messaging.subtitle | replace("-", "&#8209;") | safe }}
</p>

<!-- AI Chat Interface -->
{% include "components/ai-chat-interface.njk" %}

Expand All @@ -73,9 +79,9 @@ hubspot:
<div class="text-center mt-16 mb-8">
<h5 class="text-gray-600 mb-12">Or get a quick look at FlowFuse in 90 seconds</h5>
<div class="flex justify-center items-end m-auto">
<lite-youtube
<lite-youtube
videoid="9i-EKcNksvk"
params="rel=0"
params="rel=0"
style="width: 1024px; overflow: hidden; background-image: url('https://img.youtube.com/vi/9i-EKcNksvk/maxresdefault.jpg'); background-size: cover; background-position: center;"
class="border-4 border-indigo-200 rounded-xl sm:max-w-none sm:max-h-full">
</lite-youtube>
Expand Down
35 changes: 35 additions & 0 deletions src/js/bending-grid.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const grid = document.getElementById('hero-grid');
const fadeTop = document.getElementById('grid-fade-top');

if (grid && fadeTop) {
// Configuration - Only rotation animation
const config = {
startRotateX: 75, // More angled at start
endRotateX: 0,
scrollDistance: 30,
startFadeHeight: 42,
endFadeHeight: 8,
};

function lerp(start, end, progress) {
return start + (end - start) * progress;
}

function updateGrid() {
const scrollY = window.scrollY;
const vh = window.innerHeight;

const progress = Math.min(scrollY / (vh * (config.scrollDistance / 100)), 1);

const rotateX = lerp(config.startRotateX, config.endRotateX, progress);
const fadeHeight = lerp(config.startFadeHeight, config.endFadeHeight, progress);

// ONLY rotate angle - no position changes
grid.style.transform = `rotateX(${rotateX}deg)`;

fadeTop.style.height = `${fadeHeight}%`;
}

window.addEventListener('scroll', updateGrid, { passive: true });
updateGrid();
}