import React, { useEffect, useState, useRef } from 'react';
import { motion, AnimatePresence, useScroll, useTransform } from 'framer-motion';
import { Button } from './components/Button';
import { SectionHeader } from './components/SectionHeader';
import { WORK_SECTIONS as DEFAULT_WORK_SECTIONS, PROCESS, SERVICE_DETAILS } from './constants';
import { PortfolioItem, WorkCategory } from './types';
const fadeInUp = {
initial: { opacity: 0, y: 40 },
whileInView: { opacity: 1, y: 0 },
viewport: { once: true, margin: "-100px" },
transition: { duration: 1.2, ease: [0.22, 1, 0.36, 1] as [number, number, number, number] }
};
const staggerContainer = {
initial: {},
whileInView: {
transition: {
staggerChildren: 0.15,
}
},
viewport: { once: true, margin: "-100px" }
};
const ParallaxMedia = ({ item, isHovered }: { item: PortfolioItem; isHovered: boolean }) => {
const [isLoaded, setIsLoaded] = useState(false);
const [isPlaying, setIsPlaying] = useState(true);
const [isMuted, setIsMuted] = useState(true);
const [volume, setVolume] = useState(0.5);
const ref = useRef
(null);
const videoRef = useRef(null);
const { scrollYProgress } = useScroll({
target: ref,
offset: ["start end", "end start"]
});
const y = useTransform(scrollYProgress, [0, 1], ["-10%", "10%"]);
useEffect(() => {
if (videoRef.current) {
if (isHovered) {
if (isPlaying) videoRef.current.play().catch(() => {});
} else {
videoRef.current.pause();
}
}
}, [isHovered, isPlaying]);
const togglePlay = (e: React.MouseEvent) => {
e.stopPropagation();
if (!videoRef.current) return;
if (isPlaying) {
videoRef.current.pause();
} else {
videoRef.current.play().catch(() => {});
}
setIsPlaying(!isPlaying);
};
const toggleMute = (e: React.MouseEvent) => {
e.stopPropagation();
if (!videoRef.current) return;
const nextMuted = !isMuted;
videoRef.current.muted = nextMuted;
setIsMuted(nextMuted);
if (!nextMuted && videoRef.current.volume === 0) {
videoRef.current.volume = volume || 0.5;
}
};
const handleVolumeChange = (e: React.ChangeEvent) => {
e.stopPropagation();
const val = parseFloat(e.target.value);
setVolume(val);
if (videoRef.current) {
videoRef.current.volume = val;
if (val > 0) {
videoRef.current.muted = false;
setIsMuted(false);
} else {
setIsMuted(true);
}
}
};
return (
setIsLoaded(true)}
initial={{ opacity: 0 }}
animate={{ opacity: isLoaded ? (item.videoUrl && isHovered ? 0 : 1) : 0 }}
transition={{ duration: 1, ease: "easeOut" }}
style={{ y, height: "120%", top: "-10%", position: "absolute" }}
className="w-full object-cover filter brightness-50"
/>
{item.videoUrl && (
<>
e.stopPropagation()}
>
>
)}
);
};
interface IntakeSectionProps {
title: string;
children: React.ReactNode;
}
const IntakeSection: React.FC = ({ title, children }) => (
);
const IntakeField = ({ label, placeholder, type = "text", helper }: { label: string, placeholder?: string, type?: string, helper?: string }) => (
{label}
{type === "textarea" ? (
) : (
)}
{helper && {helper} }
);
const App: React.FC = () => {
const [scrolled, setScrolled] = useState(false);
const [isDetailOpen, setIsDetailOpen] = useState(false);
const [isIntakeFormOpen, setIsIntakeFormOpen] = useState(false);
const [isEditMode, setIsEditMode] = useState(false);
const [activeLayer, setActiveLayer] = useState(null);
const [workSections, setWorkSections] = useState(DEFAULT_WORK_SECTIONS);
const [editingItem, setEditingItem] = useState<{sectionId: string, itemId: string} | null>(null);
const manifestoRef = useRef(null);
const fileInputRef = useRef(null);
const { scrollYProgress: manifestoScroll } = useScroll({
target: manifestoRef,
offset: ["start end", "end start"]
});
const manifestoParallaxY = useTransform(manifestoScroll, [0, 1], ["-15%", "15%"]);
useEffect(() => {
const saved = localStorage.getItem('rebellion_work');
if (saved) {
try {
setWorkSections(JSON.parse(saved));
} catch (e) {
console.error("Failed to parse saved work");
}
}
}, []);
const saveWork = (updated: WorkCategory[]) => {
setWorkSections(updated);
localStorage.setItem('rebellion_work', JSON.stringify(updated));
};
useEffect(() => {
const handleScroll = () => {
setScrolled(window.scrollY > 50);
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
useEffect(() => {
if (isDetailOpen || isIntakeFormOpen || activeLayer) {
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = 'unset';
}
}, [isDetailOpen, isIntakeFormOpen, activeLayer]);
const handleFileUpload = (e: React.ChangeEvent) => {
const file = e.target.files?.[0];
if (file && editingItem) {
const url = URL.createObjectURL(file);
const isVideo = file.type.startsWith('video/');
const newSections = workSections.map(section => {
if (section.id === editingItem.sectionId) {
return {
...section,
items: section.items.map(item => {
if (item.id === editingItem.itemId) {
return {
...item,
[isVideo ? 'videoUrl' : 'imageUrl']: url
};
}
return item;
})
};
}
return section;
});
saveWork(newSections);
setEditingItem(null);
}
};
const updateItemText = (sectionId: string, itemId: string, field: keyof PortfolioItem, value: string) => {
const newSections = workSections.map(section => {
if (section.id === sectionId) {
return {
...section,
items: section.items.map(item => {
if (item.id === itemId) {
return { ...item, [field]: value };
}
return item;
})
};
}
return section;
});
saveWork(newSections);
};
const closeLayer = () => setActiveLayer(null);
return (
{activeLayer === 'archive' && (
The Proof of Concept
The Archive.
This archive is a record of restraint. We do not categorize by industry, because strategic clarity is universal.
What follows is the evidence of decisions made in favor of permanence. From enterprise protocol to human narratives, each asset is engineered to establish immediate, unquestionable authority.
Core Focus
• Cinematic consistency over variety
• Strategic logic over visual trend
• Narrative control over marketing hype
{ closeLayer(); setIsIntakeFormOpen(true); }} />
)}
{activeLayer === 'manifesto' && (
Clarity is the ultimate rebellion in a world of scale.
Vision over Explanation
If you have to explain your position, the moment is lost. We prioritize the cinematic statement that commands absolute understanding.
Clarity over Noise
Marketing noise is the sound of desperation. Strategic clarity is the sound of authority. We favor silence where it builds tension and focus.
Restraint over Volume
Volume is not impact. We do not build content cycles; we architect definitive assets that exist beyond the feed.
The Smart Rebellion is led by a strategist-turned-cinematic storyteller, with a background in corporate transformation and growth projects across Europe. Based in Belgium. Working internationally.
{ closeLayer(); setIsIntakeFormOpen(true); }} />
)}
{activeLayer === 'service' && (
Operational Standard
The One Definitive Asset.
Service Definition
A 70–80 second cinematic centerpiece. Optimized for brand positioning, sales logic, and high-level presentations.
Scope of Delivery
• Strategic Scripting & Narrative Logic
• High-End Cinematic Production
• Precision Grading & Sound Architecture
• Full Intellectual Property Transfer
$2,500 Fixed Engagement
Strict 14-day production window.
The 14-Day Lifecycle
{[
{ day: "1-3", task: "Intake & Foundation", detail: "Alignment on strategic intent and narrative logic. Script delivery." },
{ day: "4-10", task: "Synthesis", detail: "Visual production, editorial layering, and cinematic sound mapping." },
{ day: "11-14", task: "Refinement", detail: "Color grading, review cycle, and high-res delivery." }
].map((step, idx) => (
Day {step.day}
{step.task}
{step.detail}
))}
{ closeLayer(); setIsIntakeFormOpen(true); }} />
)}
{isDetailOpen && (
setIsDetailOpen(false)}
className="absolute top-6 right-6 md:top-10 md:right-10 text-gray-500 hover:text-white transition-colors p-2"
>
Production Standards
Cinematic Ad Service
{SERVICE_DETAILS.scope.map((item, idx) => (
{item.label}
{item.detail}
))}
Implementation
{SERVICE_DETAILS.useCases.map((useCase, idx) => (
0{idx+1}
{useCase}
))}
Lifecycle
{SERVICE_DETAILS.timeline.map((step, idx) => (
))}
$2,500 fixed engagement
Operational window: February 2026
Production slots are confirmed upon payment.
{ setIsDetailOpen(false); setIsIntakeFormOpen(true); }} />
)}
{isIntakeFormOpen && (
The Smart Rebellion
Production Intake
setIsIntakeFormOpen(false)}
className="text-gray-500 hover:text-white p-4 transition-colors uppercase text-[9px] tracking-ultra"
>
Close
{
alert("Intake brief received. Production synthesis begins shortly.");
setIsIntakeFormOpen(false);
}}
/>
By submitting, you initiate the 14-day production lifecycle.
)}
{ window.scrollTo({ top: 0, behavior: 'smooth' }); closeLayer(); }}
>
THE SMART REBELLION
{isEditMode && (
Editor
)}
setIsEditMode(!isEditMode)}
className={`transition-colors flex items-center gap-2 ${isEditMode ? 'text-white' : 'hover:text-white'}`}
>
{isEditMode ? 'Exit Editor' : 'Manage Work'}
setActiveLayer('archive')} className={`${activeLayer === 'archive' ? 'text-white' : 'hover:text-white'} transition-colors uppercase tracking-widest`}>Archive
setActiveLayer('manifesto')} className={`${activeLayer === 'manifesto' ? 'text-white' : 'hover:text-white'} transition-colors uppercase tracking-widest`}>Manifesto
setActiveLayer('service')} className={`${activeLayer === 'service' ? 'text-white' : 'hover:text-white'} transition-colors uppercase tracking-widest`}>Service
setIsIntakeFormOpen(true)}
/>
Strategic Intent — Cinematic Execution
Replace explanation with vision.
We eliminate the need for repeated pitching by building high-impact cinematic assets that command absolute authority.
{
document.getElementById('work')?.scrollIntoView({ behavior: 'smooth' });
}} />
setIsIntakeFormOpen(true)} />
Begin Descent
{workSections.map((section, sectionIdx) => (
Section 0{sectionIdx + 1}
{section.title}
{section.intro}
{section.guidance && (
)}
{section.items.map((item) => {
const [isCardHovered, setIsCardHovered] = useState(false);
return (
setIsCardHovered(true)}
onMouseLeave={() => setIsCardHovered(false)}
className="group relative aspect-video overflow-hidden bg-black cursor-pointer"
>
{isEditMode && (
)}
{item.internalLabel}
{item.title}
{item.oneLiner}
{!isEditMode && (
)}
);
})}
))}
Calm Authority
Hype is for the desperate. We prioritize a visual language that respects the intelligence of your audience, favoring intentional silence over marketing noise.
Narrative Focus
Visuals without story are merely decoration. We architect emotional arcs designed to bridge the gap between initial curiosity and absolute conviction.
Impact
The Service
One Definitive Asset.
A 70–80 second cinematic centerpiece. Optimized for brand positioning, sales logic, and high-level presentations.
setActiveLayer('service')} className="px-8 py-4 text-sm font-medium transition-all duration-500 uppercase tracking-widest border border-black/20 text-black hover:border-black hover:bg-black/5">Specification
Limited Availability
{['Strategic Scripting', 'Cinematic Grading', 'Rich Soundscapes', 'Fast Turnaround'].map((feature, i) => (
{feature}
))}
Commission
$2,500
net
Fixed engagement. No hidden cycles.
setIsIntakeFormOpen(true)} />
Strict 14-day production window
Production slots are confirmed upon payment.
{PROCESS.map((step) => (
0{step.number.replace('0','')}
{step.title}
{step.description}
))}
End the pitching. Start the story.
setIsIntakeFormOpen(true)} />
Production slots are confirmed upon payment.
THE SMART REBELLION
Founded by a former corporate strategist turned cinematic storyteller. Based in Belgium.
Legal
Confidentiality
setActiveLayer('archive')} className="hover:text-white transition-colors uppercase">Archive
© 2026 Rebellion Cinematic Strategy
);
};
export default App;