Content loader utility, Content directory structuur

This commit is contained in:
colinislit
2025-11-15 22:06:48 +01:00
parent dbde412465
commit 690e7b7c43
37 changed files with 9447 additions and 1035 deletions

View File

@@ -0,0 +1,214 @@
# 🎨 Design Review: Dot Shader Background Component
**Datum:** 15-11-2024
**Review Team:** Design & UX
**Vraag:** Kan het dot-shader-background component gebruikt worden voor marketingpagina en/of EPD app?
---
## 📋 Context Analyse
### Manifesto Kernwaarden
- **Innovatie & Disruptie:** "AI gaat software eten" - technologische vooruitgang centraal
- **Snelheid:** "4 weken vs 12 maanden" - efficiency en moderniteit
- **Bewijs door doen:** "Beste manier om toekomst te voorspellen is hem bouwen"
- **Digitale transformatie:** Software on Demand als nieuwe realiteit
### UX Stylesheet Principes
- **Lage cognitieve belasting:** Focus op content, niet op decoratie
- **Toegankelijkheid:** WCAG AA contrast, geen afleidende elementen
- **"Less is more":** Accentpalet bewust klein gehouden → minder visuele ruis
- **Functioneel design:** Elke visuele keuze moet doel dienen
### Shader Component Eigenschappen
- **Technisch:** Three.js shader met WebGL rendering
- **Visueel:** Geanimeerde dots met mouse trail interactie
- **Performance:** High-performance mode, GPU-accelerated
- **Theme support:** Dark/light mode compatible
- **Subtiel:** Lage opacity (0.025-0.15), niet dominant
---
## 🎯 Design Team Advies
### ✅ **AANBEVELING: Strategische Inzet**
Het design team adviseert **gecontroleerd gebruik** van het shader component, met duidelijke context-specifieke richtlijnen:
---
## 📍 Marketing Website: **JA, met voorwaarden**
### Waarom het werkt:
1. **Manifesto alignment:** Het component straalt technologische innovatie uit - perfect voor "Software on Demand" messaging
2. **Differentiatie:** Visueel onderscheidend van traditionele SaaS-landing pages
3. **Engagement:** Mouse trail interactie verhoogt tijd op pagina
4. **Credibility:** Toont technische vaardigheid zonder te overdrijven
### Implementatie Richtlijnen:
**Hero Section (Primaire Inzet)**
- ✅ Shader als full-screen achtergrond achter hero content
- ✅ Zeer lage opacity (0.02-0.05) - subtiel, niet dominant
- ✅ Content overlay met sterke contrast (wit op donker, of donker op licht)
- ✅ Performance: Lazy load alleen wanneer hero in viewport
**Secties (Secundaire Inzet)**
- ⚠️ Optioneel in "How it Works" of "Technology" secties
- ❌ NIET in comparison tables, ROI calculator, of formulier secties
- ❌ NIET op mobile (performance + UX overwegingen)
**Technische Aanpassingen Nodig:**
```typescript
// Marketing-specifieke configuratie
const marketingConfig = {
dotOpacity: 0.03, // Zeer subtiel
gridSize: 80, // Fijner grid voor eleganter effect
disableMouseTrail: false, // Interactiviteit behouden
performanceMode: 'high', // GPU optimization
mobileFallback: 'gradient' // Fallback voor mobile
}
```
**Contrast Check:**
- Tekst op shader achtergrond moet voldoen aan WCAG AA (4.5:1)
- Gebruik semi-transparante overlay indien nodig
- Test met verschillende tekstgroottes
---
## 🏥 EPD App: **NEE, tenzij zeer subtiel**
### Waarom het risicovol is:
1. **Cognitieve belasting:** Medische professionals hebben focus nodig - animaties zijn afleidend
2. **UX Stylesheet conflict:** Direct tegenstrijdig met "lage cognitieve belasting" principe
3. **Toegankelijkheid:** Kan problemen veroorzaken voor gebruikers met motion sensitivity
4. **Performance:** Elke milliseconde telt in productie-omgevingen
### Uitzondering: Onboarding/Welcome Screen
-**Alleen** op eerste login/welcome screen
- ✅ Zeer korte duur (3-5 seconden), dan fade-out
- ✅ Optioneel: "Skip animation" knop voor toegankelijkheid
-**NOOIT** tijdens actieve workflows (intake, profiel, behandelplan)
**Implementatie Als Uitzondering:**
```typescript
// EPD-specifieke configuratie (alleen welcome)
const epdWelcomeConfig = {
dotOpacity: 0.01, // Extreem subtiel
gridSize: 120, // Zeer fijn grid
disableMouseTrail: true, // Geen interactiviteit
autoFadeOut: true, // Fade na 3 seconden
skipButton: true, // Toegankelijkheid
reducedMotion: true // Respecteer prefers-reduced-motion
}
```
---
## 🎨 Stylesheet Matching Analyse
### Kleuren Compatibiliteit
**Light Theme Match:**
- ✅ Shader bg: `#F4F5F5` matcht stylesheet `#F8FAFC` (zeer dichtbij)
- ✅ Shader dots: `#e1e1e1` matcht border kleur `#E2E8F0` (harmonisch)
- ⚠️ Aanpassing nodig: Shader moet exact `#F8FAFC` gebruiken voor consistency
**Dark Theme Match:**
- ✅ Shader bg: `#121212` is acceptabel voor dark mode
- ✅ Shader dots: `#FFFFFF` met lage opacity werkt goed
- ⚠️ Stylesheet heeft geen dark mode spec gedefinieerd - dit moet eerst worden uitgewerkt
**Aanbevolen Aanpassingen:**
```typescript
// Update shader theme colors om exact te matchen
const getThemeColors = () => {
switch (theme) {
case 'light':
return {
dotColor: '#E2E8F0', // Match border color
bgColor: '#F8FAFC', // Match app background
dotOpacity: 0.03 // Zeer subtiel voor marketing
}
case 'dark':
return {
dotColor: '#475569', // Match secondary text
bgColor: '#0F172A', // Match primary text (inverted)
dotOpacity: 0.02 // Nog subtieler voor dark
}
}
}
```
---
## ⚖️ "Less is More" vs "Digital Innovation"
### Design Team Consensus:
**Marketing Website:**
- **"Less is more"** geldt voor **content en copy** - niet voor visuele impact
- Shader component kan **strategisch** gebruikt worden om innovatie te communiceren
- **Voorwaarde:** Het moet de boodschap versterken, niet afleiden
- **Test:** A/B test met en zonder shader - meet engagement metrics
**EPD App:**
- **"Less is more"** is hier **absoluut** - elke pixel moet functioneel zijn
- Shader component is **decoratief** en voegt geen functionele waarde toe
- **Uitzondering:** Welcome screen kan één keer indruk maken, daarna weg
---
## 📊 Risico Analyse
| Risico | Kans | Impact | Mitigatie |
|--------|------|--------|-----------|
| **Performance impact** | Medium | Hoog | Lazy loading, mobile fallback, performance monitoring |
| **Toegankelijkheid issues** | Medium | Hoog | `prefers-reduced-motion` respecteren, skip optie |
| **Cognitieve overload** | Hoog | Medium | Zeer lage opacity, alleen hero section |
| **Stylesheet mismatch** | Laag | Laag | Kleuren aanpassen naar exacte stylesheet waarden |
| **Mobile performance** | Hoog | Medium | Automatische fallback naar gradient |
---
## ✅ Finale Aanbeveling
### Marketing Website: **GO** ✅
- Implementeer in hero section met zeer lage opacity
- Pas kleuren aan naar exacte stylesheet waarden
- Voeg mobile fallback toe
- Monitor performance metrics
- Test toegankelijkheid met screen readers
### EPD App: **NO GO** ❌
- **Behalve:** Welcome screen (één keer, met skip optie)
- Focus op functioneel design volgens UX stylesheet
- Gebruik subtiele gradients of solid colors voor achtergronden
### Implementatie Prioriteit:
1. **Week 1:** Marketing hero section met shader (als MVP)
2. **Week 2:** Performance optimalisatie + mobile fallback
3. **Week 4:** A/B test resultaten evalueren
4. **Post-launch:** Beslissing over permanente implementatie
---
## 🎯 Design Principes Samenvatting
**Voor Marketing:**
> "Innovatie moet zichtbaar zijn, maar niet opdringerig"
**Voor EPD:**
> "Elke visuele keuze moet de gebruiker helpen, niet afleiden"
**Algemeen:**
> "Technologie moet de boodschap dienen, niet domineren"
---
**Design Team Sign-off:**
✅ Marketing website: Goedkeuring met voorwaarden
❌ EPD app: Afwijzing (behalve welcome screen)
📝 Stylesheet aanpassingen: Vereist voor consistency

View File

@@ -0,0 +1,403 @@
# 🚀 Marketing Shader Implementation Guide
**Doel:** Praktische implementatie van dot-shader component voor marketing website hero section.
---
## 📐 Design Specificaties
### Hero Section Layout
```
┌─────────────────────────────────────┐
│ [Shader Background - zeer subtiel] │
│ │
│ ┌─────────────────────────────┐ │
│ │ Hero Content Overlay │ │
│ │ - Headline (wit/donker) │ │
│ │ - Subheadline │ │
│ │ - CTA Buttons │ │
│ │ - Live Metrics Counter │ │
│ └─────────────────────────────┘ │
│ │
└─────────────────────────────────────┘
```
### Visuele Hiërarchie
1. **Shader:** Opacity 0.02-0.03 (bijna onzichtbaar, maar aanwezig)
2. **Content Overlay:** Semi-transparant of solid (afhankelijk van contrast)
3. **Tekst:** Hoog contrast (wit op donker, of donker op licht)
---
## 🔧 Technische Implementatie
### Stap 1: Aangepaste Marketing Variant
```typescript
// components/ui/marketing-shader-background.tsx
'use client'
import { DotScreenShader } from './dot-shader-background'
import { useTheme } from 'next-themes'
import { useEffect, useState } from 'react'
interface MarketingShaderProps {
variant?: 'hero' | 'section'
className?: string
}
export function MarketingShader({ variant = 'hero', className }: MarketingShaderProps) {
const { theme } = useTheme()
const [mounted, setMounted] = useState(false)
const [reducedMotion, setReducedMotion] = useState(false)
useEffect(() => {
setMounted(true)
// Check for reduced motion preference
const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)')
setReducedMotion(mediaQuery.matches)
const handleChange = (e: MediaQueryListEvent) => setReducedMotion(e.matches)
mediaQuery.addEventListener('change', handleChange)
return () => mediaQuery.removeEventListener('change', handleChange)
}, [])
// Fallback voor mobile of reduced motion
if (!mounted || reducedMotion) {
return (
<div
className={`absolute inset-0 bg-gradient-to-br from-slate-50 via-blue-50/30 to-slate-100 ${className}`}
aria-hidden="true"
/>
)
}
// Desktop: shader component
return (
<div className={`absolute inset-0 overflow-hidden ${className}`} aria-hidden="true">
<DotScreenShader />
{/* Subtle overlay voor betere tekst leesbaarheid */}
<div className="absolute inset-0 bg-white/40 dark:bg-slate-900/40 pointer-events-none" />
</div>
)
}
```
### Stap 2: Hero Section Component
```typescript
// app/(marketing)/components/hero-section.tsx
import { MarketingShader } from '@/components/ui/marketing-shader-background'
import { LiveMetricsCounter } from './live-metrics-counter'
export function HeroSection() {
return (
<section className="relative min-h-screen flex items-center justify-center overflow-hidden">
{/* Shader Background */}
<MarketingShader variant="hero" className="z-0" />
{/* Content Overlay */}
<div className="relative z-10 container mx-auto px-4 py-20">
<div className="max-w-4xl mx-auto text-center">
{/* Headline */}
<h1 className="text-5xl md:text-7xl font-bold text-slate-900 dark:text-white mb-6">
Software on Demand
</h1>
{/* Subheadline */}
<p className="text-xl md:text-2xl text-slate-700 dark:text-slate-300 mb-8">
Van 100.000 en 12 maanden naar 200 en 4 weken
</p>
{/* Live Metrics */}
<LiveMetricsCounter />
{/* CTAs */}
<div className="flex flex-col sm:flex-row gap-4 justify-center mt-12">
<button className="px-8 py-4 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition">
Bekijk Demo
</button>
<button className="px-8 py-4 bg-slate-200 text-slate-900 rounded-lg hover:bg-slate-300 transition">
Lees Manifesto
</button>
</div>
</div>
</div>
</section>
)
}
```
### Stap 3: Shader Component Aanpassingen
```typescript
// Aanpassingen in dot-shader-background.tsx voor marketing gebruik
// In Scene component, update getThemeColors:
const getThemeColors = () => {
switch (theme) {
case 'light':
return {
dotColor: '#E2E8F0', // Match UX stylesheet border color
bgColor: '#F8FAFC', // Match UX stylesheet app background
dotOpacity: 0.03 // Zeer subtiel voor marketing
}
case 'dark':
return {
dotColor: '#475569', // Match secondary text
bgColor: '#0F172A', // Match primary text (inverted)
dotOpacity: 0.02 // Nog subtieler
}
default:
return {
dotColor: '#E2E8F0',
bgColor: '#F8FAFC',
dotOpacity: 0.03
}
}
}
// Update gridSize voor eleganter effect
const gridSize = 80 // Fijner dan standaard 100
```
---
## 🎨 Styling Integratie
### Tailwind Classes voor Content Overlay
```css
/* Zorg voor goede contrast over shader */
.hero-content {
/* Optioneel: semi-transparante achtergrond voor tekst */
background: rgba(255, 255, 255, 0.7);
backdrop-filter: blur(10px);
/* Of: solid achtergrond met padding */
background: white;
padding: 2rem;
border-radius: 1rem;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
```
### Contrast Check
**Test Scenario's:**
1. Wit tekst op shader achtergrond → Minimaal 4.5:1 contrast
2. Donker tekst op shader achtergrond → Minimaal 4.5:1 contrast
3. Met overlay → Contrast moet verbeteren
**Tools:**
- [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/)
- Browser DevTools → Accessibility panel
---
## 📱 Mobile Responsive
### Breakpoint Strategie
```typescript
// components/ui/marketing-shader-background.tsx
export function MarketingShader({ variant, className }: MarketingShaderProps) {
const [isMobile, setIsMobile] = useState(false)
useEffect(() => {
const checkMobile = () => {
setIsMobile(window.innerWidth < 768) // Tailwind md breakpoint
}
checkMobile()
window.addEventListener('resize', checkMobile)
return () => window.removeEventListener('resize', checkMobile)
}, [])
// Mobile: gradient fallback (performance)
if (isMobile) {
return (
<div
className={`absolute inset-0 bg-gradient-to-br from-slate-50 via-blue-50/20 to-slate-100 ${className}`}
aria-hidden="true"
/>
)
}
// Desktop: shader
return <DotScreenShader />
}
```
**Reden:**
- Mobile GPU performance beperkt
- Batterij impact
- UX: Gebruikers verwachten snelle laadtijden op mobile
---
## ⚡ Performance Optimalisatie
### Lazy Loading
```typescript
import dynamic from 'next/dynamic'
// Lazy load shader alleen wanneer hero in viewport
const MarketingShader = dynamic(
() => import('@/components/ui/marketing-shader-background').then(mod => mod.MarketingShader),
{
ssr: false, // Client-side only
loading: () => <div className="absolute inset-0 bg-slate-50" />
}
)
```
### Intersection Observer
```typescript
// components/ui/marketing-shader-background.tsx
export function MarketingShader({ variant, className }: MarketingShaderProps) {
const [shouldRender, setShouldRender] = useState(false)
const ref = useRef<HTMLDivElement>(null)
useEffect(() => {
if (!ref.current) return
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setShouldRender(true)
observer.disconnect()
}
},
{ threshold: 0.1 }
)
observer.observe(ref.current)
return () => observer.disconnect()
}, [])
if (!shouldRender) {
return <div ref={ref} className={`absolute inset-0 bg-slate-50 ${className}`} />
}
return <DotScreenShader />
}
```
---
## ♿ Toegankelijkheid
### Reduced Motion Support
```typescript
// Automatisch detecteren en respecteren
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
if (prefersReducedMotion) {
// Geen animaties, statische gradient
return <StaticGradientBackground />
}
```
### Skip Animation Knop
```typescript
// Optioneel: knop om animatie uit te zetten
<button
onClick={() => setAnimationEnabled(false)}
className="sr-only focus:not-sr-only"
>
Skip animatie
</button>
```
### ARIA Labels
```typescript
<div
className="absolute inset-0"
aria-hidden="true" // Decoratief element, niet voor screen readers
role="presentation"
>
<DotScreenShader />
</div>
```
---
## 📊 Monitoring & Metrics
### Performance Tracking
```typescript
// Track shader performance
useEffect(() => {
const startTime = performance.now()
// Na render
requestAnimationFrame(() => {
const renderTime = performance.now() - startTime
if (renderTime > 100) {
console.warn('Shader render tijd hoog:', renderTime)
// Mogelijk fallback activeren
}
})
}, [])
```
### A/B Test Setup
```typescript
// Variant A: Met shader
// Variant B: Zonder shader (gradient)
const useShader = () => {
// Cookie/localStorage based variant assignment
const variant = localStorage.getItem('hero-variant') || 'A'
return variant === 'A'
}
```
**Metrics te meten:**
- Time to Interactive (TTI)
- First Contentful Paint (FCP)
- Bounce rate
- Engagement tijd
- Conversion rate
---
## ✅ Checklist
### Pre-Launch
- [ ] Shader opacity op 0.02-0.03 (zeer subtiel)
- [ ] Kleuren matchen exact UX stylesheet
- [ ] Mobile fallback geïmplementeerd
- [ ] Reduced motion support
- [ ] Contrast check gedaan (WCAG AA)
- [ ] Performance test (< 100ms render tijd)
- [ ] Lazy loading geïmplementeerd
### Post-Launch
- [ ] Performance monitoring actief
- [ ] A/B test resultaten analyseren
- [ ] Gebruikersfeedback verzamelen
- [ ] Accessibility audit uitgevoerd
---
## 🎯 Conclusie
Het shader component kan **strategisch** gebruikt worden op de marketing website, mits:
1. Zeer lage opacity (0.02-0.03)
2. Alleen in hero section
3. Mobile fallback aanwezig
4. Toegankelijkheid gewaarborgd
5. Performance geoptimaliseerd
**Resultaat:** Innovatieve uitstraling zonder UX compromissen.