adding the first version of the presentation and the initial attempt at the .meetings script

This commit is contained in:
itsamejms
2026-06-07 16:13:10 +01:00
parent 41f99557cc
commit 05c7d6aef3
34 changed files with 7623 additions and 1 deletions
+8
View File
@@ -0,0 +1,8 @@
node_modules/
build/
dist/
coverage/
.DS_Store
*.log
.env*
!.env.example
+1
View File
@@ -0,0 +1 @@
## Local AI presentation for LEDEX Portimao 2026
+13
View File
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Local AI Presentation</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
+5
View File
@@ -0,0 +1,5 @@
{
"name": "Local AI Presentation",
"description": "A responsive Sovereign/Cyber presentation carousel on Local AI for Business.",
"requestFramePermissions": []
}
File diff suppressed because it is too large Load Diff
+36
View File
@@ -0,0 +1,36 @@
{
"name": "local-ai-presentation",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite --port=5173 --host=0.0.0.0",
"build": "vite build",
"preview": "vite preview",
"clean": "rm -rf dist server.js",
"lint": "tsc --noEmit"
},
"dependencies": {
"@tailwindcss/vite": "^4.1.14",
"@vitejs/plugin-react": "^5.0.4",
"dotenv": "^17.2.3",
"express": "^4.21.2",
"lucide-react": "^0.546.0",
"motion": "^12.23.24",
"react": "^19.0.1",
"react-dom": "^19.0.1",
"vite": "^6.2.3"
},
"devDependencies": {
"@types/express": "^4.17.21",
"@types/node": "^22.14.0",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"autoprefixer": "^10.4.21",
"esbuild": "^0.25.0",
"tailwindcss": "^4.1.14",
"tsx": "^4.21.0",
"typescript": "~5.8.2",
"vite": "^6.2.3"
}
}
+248
View File
@@ -0,0 +1,248 @@
import { useState, useEffect, useRef } from 'react';
import { motion, AnimatePresence } from 'motion/react';
import { synth } from './utils/audioSynth';
import { SLIDES } from './data/slides';
import { GoalType, BudgetType } from './types';
// Slide components
import Slide1Title from './components/slides/Slide1Title';
import Slide2CloudParadox from './components/slides/Slide2CloudParadox';
import Slide3LocalAIStack from './components/slides/Slide3LocalAIStack';
import Slide4Quantization from './components/slides/Slide4Quantization';
import Slide5Pipelines from './components/slides/Slide5Pipelines';
import Slide6HardwareMatrix from './components/slides/Slide6HardwareMatrix';
import Slide7BuyersGuide from './components/slides/Slide7BuyersGuide';
import Slide8ROI from './components/slides/Slide8ROI';
import Slide9OfflineDemo from './components/slides/Slide9OfflineDemo';
// Layout components
import ControlBar from './components/layout/ControlBar';
export default function App() {
const [currentSlide, setCurrentSlide] = useState<number>(0);
const [direction, setDirection] = useState<number>(1);
const [isAutoplay, setIsAutoplay] = useState<boolean>(false);
const [soundEnabled, setSoundEnabled] = useState<boolean>(false);
// Shared state for cross-slide communication
const [selectedGoal, setSelectedGoal] = useState<GoalType>('agents');
const [procureBudget, setProcureBudget] = useState<BudgetType>('budget');
const [toastMessage, setToastMessage] = useState<string | null>(null);
const autoplayTimerRef = useRef<NodeJS.Timeout | null>(null);
const showToast = (msg: string) => {
setToastMessage(msg);
synth.playBlip();
setTimeout(() => {
setToastMessage(null);
}, 4000);
};
// Sound configuration binding
useEffect(() => {
synth.enabled = soundEnabled;
}, [soundEnabled]);
// Keyboard navigation
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'ArrowRight') {
nextSlide();
} else if (e.key === 'ArrowLeft') {
prevSlide();
}
};
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [currentSlide]);
// Autoplay effect
useEffect(() => {
if (isAutoplay) {
autoplayTimerRef.current = setInterval(() => {
setDirection(1);
setCurrentSlide((prev) => (prev + 1) % SLIDES.length);
synth.playSlideChange();
}, 7000);
} else {
if (autoplayTimerRef.current) {
clearInterval(autoplayTimerRef.current);
}
}
return () => {
if (autoplayTimerRef.current) clearInterval(autoplayTimerRef.current);
};
}, [isAutoplay]);
const nextSlide = () => {
setDirection(1);
setCurrentSlide((prev) => (prev + 1) % SLIDES.length);
synth.playSlideChange();
};
const prevSlide = () => {
setDirection(-1);
setCurrentSlide((prev) => (prev - 1 + SLIDES.length) % SLIDES.length);
synth.playSlideChange();
};
const jumpToSlide = (index: number) => {
setDirection(index > currentSlide ? 1 : -1);
setCurrentSlide(index);
synth.playSlideChange();
};
// Frame motion sliding definition
const slideVariants = {
enter: (dir: number) => ({
x: dir > 0 ? 300 : -300,
opacity: 0,
scale: 0.98
}),
center: {
x: 0,
opacity: 1,
scale: 1,
transition: {
x: { type: 'spring' as const, stiffness: 220, damping: 24 },
opacity: { duration: 0.25 },
scale: { duration: 0.3 }
}
},
exit: (dir: number) => ({
x: dir < 0 ? 300 : -300,
opacity: 0,
scale: 0.98,
transition: {
x: { duration: 0.25 },
opacity: { duration: 0.2 }
}
})
};
// Render current slide content
const renderSlide = () => {
switch (currentSlide) {
case 0:
return <Slide1Title />;
case 1:
return <Slide2CloudParadox />;
case 2:
return <Slide3LocalAIStack />;
case 3:
return <Slide4Quantization />;
case 4:
return <Slide5Pipelines showToast={showToast} />;
case 5:
return <Slide6HardwareMatrix
selectedGoal={selectedGoal}
onGoalChange={setSelectedGoal}
procureBudget={procureBudget}
onBudgetChange={setProcureBudget}
/>;
case 6:
return <Slide7BuyersGuide
showToast={showToast}
selectedGoal={selectedGoal}
procureBudget={procureBudget}
onGoalChange={setSelectedGoal}
onBudgetChange={setProcureBudget}
/>;
case 7:
return <Slide8ROI
selectedGoal={selectedGoal}
procureBudget={procureBudget}
showToast={showToast}
/>;
case 8:
return <Slide9OfflineDemo showToast={showToast} />;
default:
return <Slide1Title />;
}
};
return (
<div id="sovereign-app" className="min-h-screen bg-slate-950 text-slate-100 selection:bg-emerald-500 selection:text-slate-950 flex flex-col justify-between p-4 sm:p-6 md:p-8 relative overflow-hidden cyber-grid font-sans">
{/* Dynamic scanline overlay */}
<div className="absolute inset-0 scanline pointer-events-none opacity-20 z-10" />
{/* Background radial gradient glow */}
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[800px] h-[800px] rounded-full bg-emerald-500/5 blur-[120px] pointer-events-none" />
{/* CENTRAL CAROUSEL CONTAINER */}
<main className="w-full max-w-7xl mx-auto my-6 sm:my-8 flex-1 flex flex-col justify-center items-center z-20">
{/* Main Console Board Frame */}
<div className="w-full bg-slate-900/40 border border-slate-800/80 rounded-xl relative overflow-hidden flex flex-col backdrop-blur-md cyber-glow shadow-2xl">
{/* High-tech edge detail bracket and scan bar */}
<div className="absolute top-0 inset-x-0 h-[1px] bg-gradient-to-r from-transparent via-emerald-500/20 to-transparent" />
<div className="absolute left-0 inset-y-0 w-[1px] bg-gradient-to-b from-transparent via-emerald-500/10 to-transparent" />
{/* Console Top Info Segment */}
<div className="px-4 py-2 bg-slate-900/80 border-b border-slate-800/80 flex items-center justify-between font-mono text-[10px] text-slate-500">
<div className="flex items-center gap-4">
{/* <span className="text-emerald-500/70 font-bold">▶ INDEX_READOUT // SEC_0{currentSlide + 1}</span>
<span className="hidden sm:inline">|</span>
<span className="hidden sm:inline">GRID_COORDINATES: CL-517 // EN-891</span> */}
</div>
<div className="flex items-center gap-3">
<span className="text-[9px] px-2 py-0.5 rounded bg-slate-950 text-slate-400 border border-slate-800/80">{SLIDES[currentSlide].category}</span>
<span className="font-bold tracking-widest">0{currentSlide + 1} // 0{SLIDES.length}</span>
</div>
</div>
{/* PRIMARY ANIMATED CAROUSEL VIEWPORTS */}
<div className="relative min-h-[480px] sm:min-h-[520px] md:min-h-[580px] p-6 sm:p-8 md:p-12 overflow-hidden flex flex-col justify-center">
<AnimatePresence mode="wait" custom={direction}>
<motion.div
key={currentSlide}
custom={direction}
variants={slideVariants}
initial="enter"
animate="center"
exit="exit"
className="w-full h-full flex flex-col justify-between"
>
{renderSlide()}
</motion.div>
</AnimatePresence>
</div>
{/* LOWER CONSOLE CONTROL BAR */}
<ControlBar
currentSlide={currentSlide}
isAutoplay={isAutoplay}
onPrevSlide={prevSlide}
onNextSlide={nextSlide}
onJumpToSlide={jumpToSlide}
onToggleAutoplay={() => setIsAutoplay(!isAutoplay)}
/>
</div>
</main>
{/* Toast Notification */}
{toastMessage && (
<div className="fixed bottom-8 right-8 bg-emerald-500 text-slate-950 px-4 py-3 rounded-lg font-mono text-xs font-bold shadow-[0_0_20px_rgba(16,185,129,0.4)] z-50 animate-in fade-in slide-in-from-bottom-4">
{toastMessage}
</div>
)}
{/* Sound toggle button (optional feature) */}
{/* <button
onClick={() => setSoundEnabled(!soundEnabled)}
className="fixed top-4 right-4 p-2 rounded-lg bg-slate-900/80 border border-slate-800 text-slate-400 hover:text-emerald-400 transition-colors z-50"
title={soundEnabled ? 'Disable sound effects' : 'Enable sound effects'}
>
{soundEnabled ? '🔊' : '🔇'}
</button> */}
</div>
);
}
@@ -0,0 +1,94 @@
import { ChevronLeft, ChevronRight, Play, Pause } from 'lucide-react';
import { SLIDES } from '../../data/slides';
import { synth } from '../../utils/audioSynth';
interface ControlBarProps {
currentSlide: number;
isAutoplay: boolean;
onPrevSlide: () => void;
onNextSlide: () => void;
onJumpToSlide: (index: number) => void;
onToggleAutoplay: () => void;
}
export default function ControlBar({
currentSlide,
isAutoplay,
onPrevSlide,
onNextSlide,
onJumpToSlide,
onToggleAutoplay
}: ControlBarProps) {
const handleElementClick = () => synth.playClick();
return (
<footer className="px-4 py-3 sm:py-4 bg-slate-900/80 border-t border-slate-800/80 flex flex-col sm:flex-row items-center justify-between gap-4 font-mono z-30">
<div className="flex items-center gap-1.5 text-slate-500 text-[10px] order-3 sm:order-1">
<span className="px-1.5 py-0.5 rounded bg-slate-950 border border-slate-800 text-[9px]"></span>
<span className="px-1.5 py-0.5 rounded bg-slate-950 border border-slate-800 text-[9px]"></span>
<span className="hidden sm:inline font-sans text-[10px]">keys to navigate</span>
</div>
<div className="flex items-center gap-2 order-1 sm:order-2">
{SLIDES.map((slide, idx) => (
<button
key={slide.id}
onClick={() => {
synth.playClick();
onJumpToSlide(idx);
}}
className={`relative w-2 h-2 rounded-full cursor-pointer transition-all duration-300 ${
currentSlide === idx
? 'bg-emerald-400 w-6 shadow-[0_0_8px_rgba(16,185,129,0.5)]'
: 'bg-slate-700 hover:bg-slate-500'
}`}
title={`Jump to slide ${slide.id}: ${slide.title}`}
/>
))}
</div>
<div className="flex items-center gap-2 order-2 sm:order-3 w-full sm:w-auto justify-between sm:justify-start">
<button
onClick={() => {
handleElementClick();
onToggleAutoplay();
}}
className={`px-3 py-1.5 rounded border text-[10px] flex items-center gap-1.5 cursor-pointer transition-all duration-150 ${
isAutoplay
? 'border-emerald-500/40 bg-emerald-950/20 text-emerald-400'
: 'border-slate-800 bg-slate-950 text-slate-400 hover:text-slate-300 hover:border-slate-700'
}`}
title="Autoplay transitions through slides"
>
{isAutoplay ? <Pause className="w-3 h-3 text-emerald-400 animate-pulse" /> : <Play className="w-3 h-3" />}
<span>{isAutoplay ? 'AUTOPLAY: ON' : 'AUTOPLAY: OFF'}</span>
</button>
<div className="flex items-center gap-2">
<button
onClick={() => {
synth.playClick();
onPrevSlide();
}}
className="px-3.5 py-1.5 rounded border border-slate-800 bg-slate-950 text-slate-300 text-[10px] font-bold hover:border-slate-700 hover:text-white hover:bg-slate-900 cursor-pointer transition-all flex items-center gap-1"
>
<ChevronLeft className="w-3.5 h-3.5" />
<span>BACK</span>
</button>
<button
onClick={() => {
synth.playClick();
onNextSlide();
}}
className="px-3.5 py-1.5 rounded border border-emerald-500 bg-emerald-500 text-slate-950 text-[10px] font-black tracking-wide hover:opacity-90 hover:shadow-[0_0_10px_rgba(16,185,129,0.3)] cursor-pointer transition-all flex items-center gap-1"
>
<span>{currentSlide === SLIDES.length - 1 ? 'REPLAY' : 'NEXT'}</span>
<ChevronRight className="w-3.5 h-3.5" />
</button>
</div>
</div>
</footer>
);
}
@@ -0,0 +1,42 @@
import { motion } from 'motion/react';
import { Cpu } from 'lucide-react';
export default function Slide1Title() {
return (
<div className="flex flex-col items-center justify-center text-center py-6 sm:py-10 max-w-3xl mx-auto">
<motion.div
initial={{ scale: 0.9, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ delay: 0.1, duration: 0.5 }}
className="relative mb-10"
>
<div className="w-24 h-24 sm:w-28 sm:h-28 rounded-full border border-emerald-500/15 border-dashed flex items-center justify-center animate-[spin_40s_linear_infinite]" />
<div className="absolute inset-2 rounded-full border border-emerald-500/30 flex items-center justify-center animate-[spin_20s_linear_infinite_reverse]" />
<div className="absolute inset-4 rounded-full border-2 border-emerald-500/60 border-t-transparent border-b-transparent flex items-center justify-center animate-[spin_8s_linear_infinite]" />
<div className="absolute inset-0 m-auto w-12 h-12 rounded-full bg-emerald-950/40 border border-emerald-500/50 flex items-center justify-center">
<Cpu className="w-5 h-5 text-emerald-400 animate-pulse" />
</div>
</motion.div>
<p className="text-emerald-500 font-mono text-xs sm:text-sm tracking-widest uppercase font-bold text-glow mb-4">
INTRODUCTION
</p>
<h1 className="font-display font-extrabold text-3xl sm:text-4xl md:text-5xl lg:text-5xl text-white tracking-tight leading-tight uppercase font-glow mb-5">
The Sovereign Business Engine
</h1>
<div className="h-[2px] w-24 bg-gradient-to-r from-transparent via-emerald-500 to-transparent mb-6" />
<p className="text-slate-400 font-sans text-base sm:text-lg md:text-xl font-light leading-relaxed max-w-xl">
Unlock Secure, Zero-Cost Local AI for Algarve Entrepreneurs, Nomads & Content Creators
</p>
<div className="mt-12 flex flex-wrap gap-3 font-mono text-[10px] text-slate-400 justify-center">
<span className="px-3 py-1.5 rounded-full bg-slate-950 border border-emerald-900/30"> PRIVATE INTEL</span>
<span className="px-3 py-1.5 rounded-full bg-slate-950 border border-emerald-900/30"> DECENTRALISED</span>
<span className="px-3 py-1.5 rounded-full bg-slate-950 border border-emerald-900/30"> 0% SAAS TRANSACTION</span>
</div>
</div>
);
}
@@ -0,0 +1,107 @@
import { useState } from 'react';
import { Info } from 'lucide-react';
import { synth } from '../../utils/audioSynth';
interface ParadoxCard {
title: string;
desc: string;
detail: string;
alternative: string;
color: string;
tag: string;
}
const paradoxCards: ParadoxCard[] = [
{
title: "Client Data Leaks",
desc: "Privacy Risk",
detail: "Inputting client names, email campaigns, or proprietary concepts online sends delicate parameters straight to external tech servers.",
alternative: "Complete Sandboxed Privacy. No outbound internet transfers, keeping secret client details locked safely inside your laptop.",
color: "from-rose-500/10 to-rose-600/5 border-rose-950/40 text-rose-400",
tag: "DATA RISK"
},
{
title: "Subscription Taxes",
desc: "Licensing Cost",
detail: "Paying $20$40 per person every single month creates heavy baseline overheads for growing digital agencies or self-starters.",
alternative: "Zero-Bill Scale. Run identical models on modern laptops with zero cumulative licensing bills or user caps.",
color: "from-amber-500/10 to-amber-600/5 border-amber-950/40 text-amber-400",
tag: "CASH BURN"
},
{
title: "Wi-Fi Dependencies",
desc: "Broadband Risks",
detail: "Spotty beach Wi-Fi, hotel dropouts, or cafe broadband failures freeze active cloud access, instantly stalling content work.",
alternative: "100% Offline Power. Work continuously from the beach, a rural guest country house, or a transit plane in ultimate peace.",
color: "from-orange-500/10 to-orange-600/5 border-orange-950/40 text-orange-400",
tag: "OFFLINE DOWNTIME"
}
];
export default function Slide2CloudParadox() {
const [selectedParadox, setSelectedParadox] = useState<number | null>(null);
const handleCardClick = (idx: number) => {
synth.playClick();
setSelectedParadox(selectedParadox === idx ? null : idx);
};
return (
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 items-center max-w-6xl mx-auto w-full">
<div className="lg:col-span-4 flex flex-col justify-center">
<span className="text-emerald-500 font-mono text-xs font-bold uppercase tracking-wider mb-2">// THE CONUNDRUM</span>
<h2 className="font-display font-bold text-2xl sm:text-3xl text-white tracking-tight uppercase leading-none mb-4">
The Cloud Expense Trap
</h2>
<p className="text-slate-400 font-sans text-sm sm:text-base leading-relaxed mb-6">
Relying on big-tech online platforms invites data leakage risks, builds high monthly software subscriptions, and depends on having perfect Internet. Tap each risk card to unlock your secure local remedy.
</p>
<div className="hidden lg:flex items-center gap-2 border border-slate-800/80 rounded px-3 py-1.5 bg-slate-900/50 text-[10px] font-mono text-slate-500">
<Info className="w-3.5 h-3.5 text-emerald-400 shrink-0" />
<span>Interactive: Click each card to reveal the offline local alternative.</span>
</div>
</div>
<div className="lg:col-span-8 grid grid-cols-1 md:grid-cols-3 gap-4 w-full h-auto">
{paradoxCards.map((card, idx) => (
<div
key={idx}
id={`paradox-card-${idx}`}
onClick={() => handleCardClick(idx)}
className={`group relative p-5 rounded-lg border bg-gradient-to-b transition-all duration-300 cursor-pointer text-left flex flex-col justify-between min-h-[220px] md:min-h-[265px] ${
selectedParadox === idx
? 'border-emerald-500/65 bg-slate-950/80 shadow-[0_0_15px_rgba(16,185,129,0.15)]'
: `border-slate-800/80 bg-slate-900/60 hover:border-slate-700 hover:bg-slate-900/90`
}`}
>
<div>
<div className="flex justify-between items-start mb-4">
<span className="font-mono text-[9px] font-bold text-slate-500">PARADOX_0{idx + 1}</span>
<span className={`font-mono text-[8px] font-semibold px-2 py-0.5 rounded ${
selectedParadox === idx ? 'bg-emerald-950/40 text-emerald-400' : 'bg-slate-950/60 text-slate-400'
}`}>
{selectedParadox === idx ? 'SOVEREIGN_REMEDY' : card.tag}
</span>
</div>
<h3 className="font-display font-medium text-white text-base tracking-tight mb-2">
{selectedParadox === idx ? 'Antidote' : card.title}
</h3>
<p className="font-sans text-[12px] leading-relaxed text-slate-400">
{selectedParadox === idx ? card.alternative : card.detail}
</p>
</div>
<div className="pt-4 border-t border-slate-850 justify-self-end mt-4">
<span className="font-mono text-[9px] text-emerald-500 group-hover:underline flex items-center gap-1.5">
{selectedParadox === idx ? '← SHOW RISK METRIC' : '⚡ REVEAL LOCAL ANTIDOTE'}
</span>
</div>
</div>
))}
</div>
</div>
);
}
@@ -0,0 +1,104 @@
import { useState } from 'react';
import { Layers } from 'lucide-react';
import { synth } from '../../utils/audioSynth';
interface StackLayer {
level: number;
label: string;
desc: string;
color: string;
}
const stackLayers: StackLayer[] = [
{
level: 3,
label: "Visual Desktop Apps (The App)",
desc: "Simple visual programs like AnythingLLM or LM Studio designed for easy point-and-click work.",
color: "from-emerald-400/20 to-emerald-500/10 border-emerald-500/35 hover:scale-[1.01]"
},
{
level: 2,
label: "Open-Weights Models (The Brain)",
desc: "Highly optimized intelligence units (Llama, Mistral, Qwen) saved directly to your computer.",
color: "from-emerald-600/15 to-emerald-700/5 border-emerald-500/25 hover:scale-[1.01]"
},
{
level: 1,
label: "On-Device Processing (The Hardware)",
desc: "The fast processor chips or built-in system memory already in your office computer.",
color: "from-emerald-800/10 to-slate-900/40 border-slate-700/60 hover:scale-[1.01]"
}
];
const layerDetails: Record<number, string> = {
3: "FRIENDLY VISUAL DESKTOP APPS: Point-and-click programs that look and feel just like ChatGPT. Supports dragging files for secure offline searches, organizing text templates, and polishing emails. Popular: LM Studio, AnythingLLM, Jan.",
2: "INDEPENDENT FREE BRAINS: Highly capable modular model weights that you download once for free. Ranging in size depending on task complexity, they execute completely locally on your computer with zero monthly limits.",
1: "YOUR BUILT-IN SILICON: The physical components already inside your device. Modern Apple MacBook silicon or standard business graphics processors calculate AI answers in fractions of a second."
};
export default function Slide3LocalAIStack() {
const [activeStackLayer, setActiveStackLayer] = useState<number>(1);
const handleLayerClick = (level: number) => {
synth.playClick();
setActiveStackLayer(level);
};
return (
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 items-center max-w-6xl mx-auto w-full">
<div className="lg:col-span-5 flex flex-col justify-center">
<span className="text-emerald-500 font-mono text-xs font-bold uppercase tracking-wider mb-2">// COGNITIVE STRUCTURE</span>
<h2 className="font-display font-bold text-2xl sm:text-3xl text-white tracking-tight uppercase leading-none mb-4">
Your Private AI Workspace
</h2>
<p className="text-slate-400 font-sans text-sm sm:text-base leading-relaxed mb-6">
Running secure local AI is straightforward and divides into three simple, clear levels. Click any layer below to see how friendly desktop apps link directly to your laptop's power.
</p>
<div className="bg-slate-950/40 border border-emerald-950/30 rounded-lg p-5 font-mono text-left">
<div className="flex items-center gap-2 text-emerald-400 text-xs font-bold mb-2">
<Layers className="w-4 h-4" />
<span>LEVEL_0{activeStackLayer} SUMMARY</span>
</div>
<p className="text-[12px] leading-relaxed text-slate-300">
{layerDetails[activeStackLayer]}
</p>
</div>
</div>
<div className="lg:col-span-7 flex flex-col gap-3 items-center justify-center w-full relative">
{stackLayers.map((layer) => (
<div
key={layer.level}
id={`stack-layer-${layer.level}`}
onClick={() => handleLayerClick(layer.level)}
className={`w-full p-5 rounded-lg border text-left cursor-pointer transition-all duration-300 relative ${layer.color} ${
activeStackLayer === layer.level
? 'border-emerald-400 bg-slate-910/80 shadow-[0_0_20px_rgba(16,185,129,0.2)]'
: 'bg-slate-900/40 hover:bg-slate-900/80'
}`}
>
<div className="flex justify-between items-center mb-1">
<span className="font-mono text-[9px] tracking-widest text-emerald-400 font-bold">LEVEL_0{layer.level} SYSTEM LAYER</span>
{activeStackLayer === layer.level && (
<span className="font-mono text-[9px] text-emerald-400 text-glow flex items-center gap-1 animate-pulse">
● SELECTED_RUN
</span>
)}
</div>
<h3 className="font-display font-medium text-white text-base tracking-tight mb-1">
{layer.label}
</h3>
<p className="font-sans text-[12px] text-slate-400 leading-relaxed">
{layer.desc}
</p>
</div>
))}
<div className="absolute right-6 top-1/4 bottom-1/4 w-[1px] border-r border-dashed border-emerald-500/20 -z-10 pointer-events-none hidden md:block" />
</div>
</div>
);
}
@@ -0,0 +1,143 @@
import { useState } from 'react';
import { QuantLevel } from '../../types';
import { synth } from '../../utils/audioSynth';
interface QuantOption {
level: QuantLevel;
label: string;
ram: string;
intellect: string;
speed: string;
desc: string;
}
const quantOptions: QuantOption[] = [
{ level: 'FP16', label: 'FP16 Raw', ram: "16 GB", intellect: "100%", speed: "1.0x", desc: "No loss, heavy workload" },
{ level: 'Q8_0', label: '8-Bit (Q8)', ram: "8.5 GB", intellect: "99.1%", speed: "1.8x", desc: "Premium, lower RAM" },
{ level: 'Q4_K_M', label: '4-Bit (Q4)', ram: "4.8 GB", intellect: "96.2%", speed: "3.2x", desc: "Sovereign sweetspot" },
{ level: 'Q2_K', label: '2-Bit (Q2)', ram: "2.9 GB", intellect: "81.3%", speed: "4.5x", desc: "Highly crushed, rapid" }
];
const ramValues: Record<QuantLevel, string> = {
'FP16': '16.0 GB',
'Q8_0': '8.5 GB',
'Q4_K_M': '4.8 GB',
'Q2_K': '2.9 GB'
};
const ramPercentages: Record<QuantLevel, string> = {
'FP16': '100%',
'Q8_0': '53.1%',
'Q4_K_M': '30.0%',
'Q2_K': '18.1%'
};
const intellectValues: Record<QuantLevel, string> = {
'FP16': '100%',
'Q8_0': '99.1%',
'Q4_K_M': '96.2%',
'Q2_K': '81.3%'
};
const speedValues: Record<QuantLevel, { display: string; percent: string }> = {
'FP16': { display: '1.0x (Slow)', percent: '22%' },
'Q8_0': { display: '1.8x (Fast)', percent: '40%' },
'Q4_K_M': { display: '3.2x (Rapid)', percent: '71%' },
'Q2_K': { display: '4.5x (Ultrafast)', percent: '100%' }
};
const visualSampling: Record<QuantLevel, string> = {
'FP16': '[░░░██████████████████░░░] [Raw-grade maximum detail coordinates - extremely heavy] MAXIMUM_DETAIL',
'Q8_0': '[░░░█████████████████░░░░] [Highly accurate - lighter RAM footprint] SAFE_BUDGET',
'Q4_K_M': '[░░░░███████████████░░░░░] [Sovereign Sweet Spot - runs ultra fast on any Macbook or PC] SYSTEM_RECOMMENDED',
'Q2_K': '[░░░░░░░██████████░░░░░░░] [Crushed data structure - logic levels degraded] REDUCED_LOGIC'
};
export default function Slide4Quantization() {
const [quantLevel, setQuantLevel] = useState<QuantLevel>('Q4_K_M');
const handleQuantClick = (level: QuantLevel) => {
synth.playClick();
setQuantLevel(level);
};
return (
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 items-center max-w-6xl mx-auto w-full">
<div className="lg:col-span-5 flex flex-col justify-center">
<span className="text-emerald-500 font-mono text-xs font-bold uppercase tracking-wider mb-2">// DYNAMIC OPTIMISATION</span>
<h2 className="font-display font-bold text-2xl sm:text-3xl text-white tracking-tight uppercase leading-none mb-4">
AI Compression: Smart Scaling
</h2>
<p className="text-slate-400 font-sans text-sm leading-relaxed mb-6">
<strong>Analogy:</strong> 4K Cinema Raw vs. 1080p Stream. Quantization compresses the model parameters (e.g., 16-bit floats to 4-bit integers), cutting RAM requirements by up to 75% while retaining ~95%+ cognitive fidelity.
</p>
<div className="bg-slate-950/40 border border-slate-800/80 rounded-lg p-4 font-mono text-left">
<span className="text-[10px] text-slate-400 block mb-1">SYSTEM INSIGHT</span>
<p className="text-[11px] text-slate-400 leading-relaxed">
By compressing heavy decimal parameters to integer coordinates, we reduce the speed bottlenecks caused by bandwidth throughput limiters, yielding 3x faster local response feedback directly on simple laptops.
</p>
</div>
</div>
<div className="lg:col-span-7 flex flex-col gap-6 w-full">
<div className="bg-slate-950/60 border border-slate-800/80 rounded-xl p-5 sm:p-6 md:p-8 relative">
<div className="flex items-center justify-between font-mono text-[10px] text-slate-400 mb-6">
<span>INTERACTIVE COMPRESSION SELECTOR</span>
<span className="text-emerald-500 font-bold">MODE: {quantLevel}</span>
</div>
<div className="grid grid-cols-4 gap-2 mb-8">
{quantOptions.map((item) => (
<button
key={item.level}
onClick={() => handleQuantClick(item.level)}
className={`p-3 rounded-lg border text-center font-mono cursor-pointer transition-all duration-200 flex flex-col justify-between ${
quantLevel === item.level
? 'border-emerald-500 bg-emerald-950/25 text-emerald-400 shadow-[0_0_10px_rgba(16,185,129,0.15)]'
: 'border-slate-800 bg-slate-900/40 text-slate-400 hover:border-slate-700 hover:text-slate-200'
}`}
>
<span className="text-xs font-bold leading-none mb-1">{item.level}</span>
<span className="text-[9px] text-slate-500 font-light leading-none">{item.label}</span>
</button>
))}
</div>
<div className="grid grid-cols-3 gap-4 mb-6">
<div className="p-3 bg-slate-900/80 rounded-lg border border-slate-850">
<span className="font-mono text-[9px] text-slate-500 block mb-1 uppercase">RAM footprints</span>
<span className="font-display font-medium text-lg text-white">{ramValues[quantLevel]}</span>
<div className="w-full bg-slate-950 h-1.5 rounded-full overflow-hidden mt-1 px-0.5 relative">
<div className="h-full bg-emerald-500 transition-all duration-300" style={{ width: ramPercentages[quantLevel] }} />
</div>
</div>
<div className="p-3 bg-slate-900/80 rounded-lg border border-slate-850">
<span className="font-mono text-[9px] text-slate-500 block mb-1 uppercase">Intelligence Match</span>
<span className="font-display font-medium text-lg text-white">{intellectValues[quantLevel]}</span>
<div className="w-full bg-slate-950 h-1.5 rounded-full overflow-hidden mt-1 px-0.5">
<div className="h-full bg-emerald-500 transition-all duration-300" style={{ width: intellectValues[quantLevel] }} />
</div>
</div>
<div className="p-3 bg-slate-900/80 rounded-lg border border-slate-850">
<span className="font-mono text-[9px] text-slate-500 block mb-1 uppercase">Output Speedup</span>
<span className="font-display font-medium text-lg text-emerald-400">{speedValues[quantLevel].display}</span>
<div className="w-full bg-slate-950 h-1.5 rounded-full overflow-hidden mt-1 px-0.5">
<div className="h-full bg-emerald-400 transition-all duration-300" style={{ width: speedValues[quantLevel].percent }} />
</div>
</div>
</div>
<div className="p-3 bg-slate-950 rounded border border-slate-850 font-mono text-left relative overflow-hidden">
<span className="text-[9px] text-slate-500 block mb-1">VISUAL VECTOR SAMPLING GRAPHICS:</span>
<div className="text-[10px] sm:text-xs text-slate-300 tracking-normal break-all select-none">
{visualSampling[quantLevel]}
</div>
</div>
</div>
</div>
</div>
);
}
@@ -0,0 +1,432 @@
import { useState } from 'react';
import { RefreshCw, Copy, Brain, Tags, TrendingUp, Mail } from 'lucide-react';
import { synth } from '../../utils/audioSynth';
type PipelineType = 'triage' | 'classifier' | 'leads';
interface PipelineOption {
id: PipelineType;
label: string;
icon: React.ReactNode;
description: string;
}
const pipelineOptions: PipelineOption[] = [
{
id: 'triage',
label: '📧 EMAIL TRIAGE',
icon: <Mail className="w-4 h-4" />,
description: 'Auto-categorize & prioritize inbox'
},
{
id: 'classifier',
label: '🏷️ CONTENT TAGGER',
icon: <Tags className="w-4 h-4" />,
description: 'Classify content by type & tone'
},
{
id: 'leads',
label: '📊 LEAD SCORER',
icon: <TrendingUp className="w-4 h-4" />,
description: 'Score & rank sales prospects'
}
];
const sampleInputs: Record<PipelineType, string> = {
triage: `From: Maria Santos <maria@techstartup.pt>
Subject: URGENT - Partnership proposal for AI automation
Hi team, we're looking to implement local AI across our 50-person marketing agency. Need quote by Friday. Budget: €15k.
---
From: João Pereira <joao@algarvevillas.com>
Subject: Re: Villa booking inquiry #4821
Thank you for the quick response! Can you send availability for July 15-22? 6 guests.
---
From: billing@cloudservice.io
Subject: Invoice #8821 - Payment Overdue
Your account is 30 days past due. Immediate payment required to avoid suspension.`,
classifier: `POST 1: "Just closed our biggest deal using local AI! No more monthly fees, zero data leaks. Algarve businesses, this is the future! 🚀 #LocalAI #BusinessGrowth"
POST 2: "New blog: 5 Ways Local AI Transforms Content Workflows in 2025. Read how Portuguese companies save €50k/year by going offline-first."
POST 3: "Limited offer: Free local AI setup consultation for Faro-based startups. DM for details. Professional, secure, unlimited."`,
leads: `Company: TechLisbon Solutions | Contact: Ana Costa (CEO) | Need: Company-wide AI deployment | Budget: €50k+ | Timeline: Q3 2025 | Employees: 85
Company: Algarve Digital Marketing | Contact: Pedro Silva (Founder) | Need: Content automation pipeline | Budget: €8k | Timeline: ASAP | Employees: 12
Company: Porto E-commerce Hub | Contact: Sofia Mendes (CTO) | Need: Customer support AI agents | Budget: €25k | Timeline: Next quarter | Employees: 45`
};
export default function Slide5Pipelines({ showToast }: { showToast: (msg: string) => void }) {
const [selectedPipeline, setSelectedPipeline] = useState<PipelineType>('triage');
const [rawText, setRawText] = useState<string>(sampleInputs.triage);
const [pipelineProcessing, setPipelineProcessing] = useState<boolean>(false);
const [results, setResults] = useState<any[] | null>(null);
const handlePipelineChange = (type: PipelineType) => {
synth.playClick();
setSelectedPipeline(type);
setRawText(sampleInputs[type]);
setResults(null);
};
const executePipeline = () => {
synth.playBlip();
setPipelineProcessing(true);
setResults(null);
setTimeout(() => {
let processedResults: any[] = [];
if (selectedPipeline === 'triage') {
const emails = rawText.split('---').filter(Boolean);
processedResults = emails.map((email, idx) => {
const lines = email.split('\n');
const fromMatch = lines.find(l => l.startsWith('From:'));
const subjectMatch = lines.find(l => l.startsWith('Subject:'));
const from = fromMatch ? fromMatch.replace('From: ', '').split('<')[0].trim() : 'Unknown';
const subject = subjectMatch ? subjectMatch.replace('Subject: ', '') : 'No subject';
const isUrgent = email.toLowerCase().includes('urgent') || email.toLowerCase().includes('asap');
const isBilling = email.toLowerCase().includes('invoice') || email.toLowerCase().includes('payment');
const isPartnership = email.toLowerCase().includes('partnership') || email.toLowerCase().includes('proposal');
const isSupport = email.toLowerCase().includes('booking') || email.toLowerCase().includes('inquiry');
let category: 'sales' | 'support' | 'billing' | 'partnership' = 'support';
if (isBilling) category = 'billing';
else if (isPartnership) category = 'partnership';
else if (isUrgent) category = 'sales';
let priority: 'critical' | 'high' | 'normal' | 'low' = 'normal';
if (isUrgent || isBilling) priority = 'critical';
else if (isPartnership) priority = 'high';
let sentiment: 'positive' | 'neutral' | 'negative' = 'neutral';
if (email.includes('Thank you') || email.includes('great')) sentiment = 'positive';
if (email.includes('Overdue') || email.includes('suspension')) sentiment = 'negative';
return {
id: `EMAIL-${String(idx + 1).padStart(3, '0')}`,
sender: from,
subject: subject,
category,
priority,
sentiment,
actionRequired: priority === 'critical' ? 'Respond within 2 hours' : 'Review within 24 hours'
};
});
} else if (selectedPipeline === 'classifier') {
const posts = rawText.split('POST').filter(Boolean);
processedResults = posts.map((post, idx) => {
const content = post.split('"')[1] || post;
const hasEmoji = /[🚀💡📈]/.test(content);
const hasHashtag = content.includes('#');
const hasLink = content.toLowerCase().includes('read') || content.toLowerCase().includes('blog');
const hasOffer = content.toLowerCase().includes('offer') || content.toLowerCase().includes('free');
let type: 'blog' | 'social' | 'email' | 'ad_copy' = 'social';
if (hasLink) type = 'blog';
if (hasOffer) type = 'ad_copy';
let tone: 'professional' | 'casual' | 'persuasive' | 'informative' = 'professional';
if (hasEmoji) tone = 'casual';
if (hasOffer) tone = 'persuasive';
if (type === 'blog') tone = 'informative';
const keywords: string[] = [];
if (content.includes('AI')) keywords.push('AI');
if (content.includes('business')) keywords.push('business');
if (content.includes('local')) keywords.push('local AI');
if (content.includes('Algarve') || content.includes('Portuguese')) keywords.push('Portugal');
return {
id: `CONTENT-${String(idx + 1).padStart(3, '0')}`,
content: content.substring(0, 80) + '...',
type,
tone,
targetAudience: type === 'social' ? 'Social media followers' : 'Business decision makers',
seoKeywords: keywords.length > 0 ? keywords : ['general']
};
});
} else {
const leads = rawText.split('\n\n').filter(Boolean);
processedResults = leads.map((lead, idx) => {
const parts: Record<string, string> = {};
lead.split(' | ').forEach(part => {
const [key, value] = part.split(': ').map(s => s.trim());
if (key && value) parts[key] = value;
});
const employeeCount = parseInt(parts['Employees'] || '0');
const budgetText = parts['Budget'] || '';
const budgetValue = parseInt(budgetText.replace(/[^0-9]/g, '')) || 0;
const isAsap = parts['Timeline']?.toLowerCase().includes('asap');
let score = 50;
if (employeeCount > 50) score += 20;
else if (employeeCount > 20) score += 10;
if (budgetValue > 30000) score += 25;
else if (budgetValue > 10000) score += 15;
if (isAsap) score += 15;
let fit: 'excellent' | 'good' | 'fair' = 'fair';
if (score >= 80) fit = 'excellent';
else if (score >= 65) fit = 'good';
let budget: 'high' | 'medium' | 'low' = 'medium';
if (budgetValue > 40000) budget = 'high';
else if (budgetValue < 15000) budget = 'low';
let timeline: 'immediate' | 'this_month' | 'quarterly' = 'quarterly';
if (isAsap) timeline = 'immediate';
else if (parts['Timeline']?.toLowerCase().includes('month')) timeline = 'this_month';
return {
id: `LEAD-${String(idx + 1).padStart(3, '0')}`,
company: parts['Company'] || 'Unknown Company',
contact: parts['Contact'] || 'Unknown',
score: Math.min(100, score),
budget,
timeline,
fit,
nextStep: score >= 80 ? 'Schedule demo this week' : score >= 65 ? 'Send follow-up email' : 'Add to nurture sequence'
};
});
}
setResults(processedResults);
setPipelineProcessing(false);
synth.playBlip();
}, 1500);
};
const handleReset = () => {
synth.playClick();
setRawText(sampleInputs[selectedPipeline]);
setResults(null);
};
const handleCopy = () => {
if (results) {
synth.playClick();
navigator.clipboard.writeText(JSON.stringify(results, null, 2));
showToast("SUCCESS // PIPELINE OUTPUT COPIED TO CLIPBOARD");
}
};
const getPriorityColor = (priority: string) => {
if (priority === 'critical') return 'bg-rose-500/20 text-rose-400 border-rose-500/30';
if (priority === 'high') return 'bg-orange-500/20 text-orange-400 border-orange-500/30';
if (priority === 'normal') return 'bg-blue-500/20 text-blue-400 border-blue-500/30';
return 'bg-slate-500/20 text-slate-400 border-slate-500/30';
};
const getScoreColor = (score: number) => {
if (score >= 80) return 'text-emerald-400';
if (score >= 65) return 'text-yellow-400';
return 'text-orange-400';
};
return (
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 items-center max-w-6xl mx-auto w-full">
<div className="lg:col-span-4 flex flex-col justify-center text-left">
<span className="text-emerald-500 font-mono text-xs font-bold uppercase tracking-wider mb-2">// COGNITIVE AUTOMATION</span>
<h2 className="font-display font-bold text-2xl sm:text-3xl text-white tracking-tight uppercase leading-none mb-4">
Smart Workflow Pipelines
</h2>
<p className="text-slate-400 font-sans text-sm sm:text-base leading-relaxed mb-6">
Transform unstructured data into actionable insights. Select a pipeline type and watch local AI extract, categorize, and score your business data in milliseconds.
</p>
<div className="flex flex-col gap-3 font-mono text-[11px] text-slate-400">
<div className="flex items-center gap-2">
<span className="text-rose-500"></span>
<span>Manual sorting: 5-10 minutes per item</span>
</div>
<div className="flex items-center gap-2">
<span className="text-emerald-400"></span>
<span>Local AI pipeline: ~150ms per batch</span>
</div>
<div className="flex items-center gap-2">
<Brain className="w-3.5 h-3.5 text-emerald-400" />
<span>100% offline - zero data leaves your device</span>
</div>
</div>
</div>
<div className="lg:col-span-8 flex flex-col w-full">
<div className="bg-slate-950/60 border border-slate-800/80 rounded-xl p-5 sm:p-6 text-left flex flex-col gap-4">
<div className="flex items-center justify-between font-mono text-[10px] text-slate-400 mb-1">
<span>INTERACTIVE PIPELINE WORKSHOP</span>
<span className="text-emerald-400 font-bold"> LOCAL_ENGINE_ACTIVE</span>
</div>
{/* Pipeline Type Selector */}
<div className="grid grid-cols-3 gap-2 mb-4">
{pipelineOptions.map((option) => (
<button
key={option.id}
onClick={() => handlePipelineChange(option.id)}
className={`p-3 rounded-lg border text-left cursor-pointer transition-all duration-200 flex flex-col gap-1.5 ${
selectedPipeline === option.id
? 'border-emerald-500 bg-emerald-950/25 text-emerald-400 shadow-[0_0_12px_rgba(16,185,129,0.15)]'
: 'border-slate-800 bg-slate-900/40 text-slate-400 hover:border-slate-700 hover:text-slate-200'
}`}
>
<div className="flex items-center gap-2">
{option.icon}
<span className="text-[9px] font-bold tracking-tight">{option.label}</span>
</div>
<span className="text-[8px] font-light leading-tight">{option.description}</span>
</button>
))}
</div>
{/* Input Area */}
<div className="flex flex-col gap-1.5">
<label className="font-mono text-[9px] text-slate-500 uppercase">Input Data (Editable - Try modifying!):</label>
<textarea
value={rawText}
onChange={(e) => setRawText(e.target.value)}
className="bg-slate-900 border border-slate-800/80 rounded p-3 font-mono text-xs text-white h-32 focus:outline-none focus:border-emerald-500 transition-colors custom-scrollbar resize-none"
/>
</div>
{/* Action Buttons */}
<div className="flex justify-end gap-2.5">
<button
onClick={handleReset}
className="px-3.5 py-1.5 rounded font-mono text-[10px] bg-slate-900 text-slate-400 hover:text-slate-200 border border-slate-800 transition-colors"
>
RESET SAMPLE
</button>
<button
onClick={executePipeline}
disabled={pipelineProcessing}
className={`px-4 py-1.5 rounded font-mono text-[10px] flex items-center gap-2 cursor-pointer transition-all duration-200 border ${
pipelineProcessing
? 'bg-emerald-950/20 border-emerald-500/30 text-emerald-500'
: 'bg-emerald-500 text-slate-950 border-emerald-400 hover:shadow-[0_0_12px_rgba(16,185,129,0.3)] hover:opacity-90'
}`}
>
<RefreshCw className={`w-3.5 h-3.5 ${pipelineProcessing ? 'animate-spin' : ''}`} />
{pipelineProcessing ? 'PROCESSING...' : 'RUN PIPELINE'}
</button>
</div>
{/* Results Display */}
<div className="bg-slate-900 rounded border border-slate-850 p-4 shrink-0 min-h-[200px] flex flex-col justify-center">
{pipelineProcessing ? (
<div className="flex flex-col items-center justify-center py-6 font-mono text-xs text-slate-500">
<div className="w-10 h-10 rounded-full border-2 border-t-emerald-500 border-r-transparent border-slate-800 animate-spin mb-4" />
<p className="text-emerald-400/80 animate-pulse">RUNNING LOCAL INFERENCE...</p>
<p className="text-[10px] mt-1">Extracting patterns Scoring Categorizing</p>
</div>
) : results ? (
<div className="w-full flex flex-col gap-3">
<div className="flex justify-between items-center mb-2">
<span className="font-mono text-[9px] text-emerald-400">
PROCESSED {results.length} ITEMS IN ~150MS
</span>
<button
onClick={handleCopy}
className="flex items-center gap-1.5 text-emerald-400 border border-emerald-900/35 bg-slate-950/40 hover:bg-emerald-950/20 px-2 py-0.5 rounded transition-colors text-[9px]"
>
<Copy className="w-3 h-3" />
<span>EXPORT JSON</span>
</button>
</div>
<div className="space-y-2 max-h-64 overflow-y-auto custom-scrollbar">
{results.map((item: any, idx) => (
<div key={item.id} className="bg-slate-950/50 border border-slate-800/60 rounded p-3 hover:border-emerald-500/30 transition-colors">
{selectedPipeline === 'triage' && (
<div className="flex flex-col gap-1.5">
<div className="flex justify-between items-start">
<div>
<p className="font-sans text-xs font-medium text-white">{item.sender}</p>
<p className="font-mono text-[10px] text-slate-400">{item.subject}</p>
</div>
<div className="flex gap-1">
<span className={`px-1.5 py-0.5 rounded text-[8px] border ${getPriorityColor(item.priority)}`}>
{item.priority.toUpperCase()}
</span>
<span className="px-1.5 py-0.5 rounded text-[8px] border border-slate-700 bg-slate-800/50 text-slate-400">
{item.category}
</span>
</div>
</div>
<div className="flex justify-between items-center">
<span className={`text-[9px] ${item.sentiment === 'positive' ? 'text-emerald-400' : item.sentiment === 'negative' ? 'text-rose-400' : 'text-yellow-400'}`}>
{item.sentiment === 'positive' ? '☺ Positive' : item.sentiment === 'negative' ? '⚠ Negative' : '○ Neutral'}
</span>
<span className="font-mono text-[9px] text-slate-500">{item.actionRequired}</span>
</div>
</div>
)}
{selectedPipeline === 'classifier' && (
<div className="flex flex-col gap-1.5">
<p className="font-sans text-xs text-slate-300 italic">"{item.content}"</p>
<div className="flex flex-wrap gap-1.5">
<span className="px-1.5 py-0.5 rounded text-[8px] bg-emerald-500/20 text-emerald-400 border border-emerald-500/30">
{item.type}
</span>
<span className="px-1.5 py-0.5 rounded text-[8px] bg-blue-500/20 text-blue-400 border border-blue-500/30">
{item.tone}
</span>
<span className="px-1.5 py-0.5 rounded text-[8px] bg-slate-800/50 text-slate-400 border border-slate-700">
{item.targetAudience}
</span>
</div>
<div className="flex gap-1 flex-wrap">
{item.seoKeywords.map((kw: string, i: number) => (
<span key={i} className="text-[8px] text-emerald-500/70">#{kw}</span>
))}
</div>
</div>
)}
{selectedPipeline === 'leads' && (
<div className="flex justify-between items-center">
<div className="flex flex-col gap-1">
<p className="font-sans text-xs font-bold text-white">{item.company}</p>
<p className="font-mono text-[10px] text-slate-400">{item.contact}</p>
<div className="flex gap-2 text-[9px]">
<span className="text-slate-500">Budget: <span className={item.budget === 'high' ? 'text-emerald-400' : 'text-slate-400'}>{item.budget}</span></span>
<span className="text-slate-500">Timeline: <span className={item.timeline === 'immediate' ? 'text-emerald-400' : 'text-slate-400'}>{item.timeline.replace('_', ' ')}</span></span>
</div>
</div>
<div className="text-right">
<div className={`text-2xl font-bold ${getScoreColor(item.score)}`}>{item.score}</div>
<div className="text-[9px] text-slate-500">LEAD SCORE</div>
<div className={`text-[9px] mt-1 ${item.fit === 'excellent' ? 'text-emerald-400' : item.fit === 'good' ? 'text-yellow-400' : 'text-orange-400'}`}>
{item.fit.toUpperCase()} FIT
</div>
</div>
</div>
)}
</div>
))}
</div>
</div>
) : (
<div className="text-center font-mono py-8 text-slate-500">
<Brain className="w-12 h-12 mx-auto mb-3 text-slate-600" />
<p className="text-xs mb-1">PIPELINE STANDBY</p>
<p className="text-[10px] font-sans">Select a pipeline type above and click "RUN PIPELINE" to process data locally.</p>
</div>
)}
</div>
</div>
</div>
</div>
);
}
@@ -0,0 +1,322 @@
import { useState } from 'react';
import { Cpu, Sparkles, ArrowRight } from 'lucide-react';
import { BudgetType, Slide6Tab, GoalType } from '../../types';
import { synth } from '../../utils/audioSynth';
interface HardwareRow {
id: number;
tier: string;
hardware: string;
models: string;
capacity: string;
}
const hardwareRows: HardwareRow[] = [
{
id: 0,
tier: "Baseline: 16GB RAM",
hardware: "Office Laptops (M1/M2/M3 Macbook Air, Intel Core i7 with integrated Iris)",
models: "Llama 3 8B, Qwen 2.5 7B, Mistral 7B (Q4_K_M)",
capacity: "Low Latency Single Task"
},
{
id: 1,
tier: "Sweet Spot: 32GB-48GB RAM",
hardware: "Developer Workstations (Macbook Pro M3 Max, Nvidia RTX 4070/4080 Super)",
models: "Qwen 2.5 14B/32B, Phi-3-Medium, Command R",
capacity: "Multi-Agent Pipelines & Full RAG"
},
{
id: 2,
tier: "Enterprise: 64GB+ RAM",
hardware: "In-House Server Nodes (Mac Studio, Dual NVIDIA RTX 4090, Host Workstations)",
models: "Llama 3 70B (Q4), Mixtral 8x22B Mixture of Experts",
capacity: "Parallel Enterprise API Replacement"
}
];
const hardwareDetails: Record<number, string> = {
0: "BASELINE CAPABILITY: Perfect for running 3B-8B parameters quantized models at peak speed. Integrates simple office assistants, direct translation pipelines, and localized structured search indexing without lags.",
1: "HIGH PERFORMANCE (SWEET SPOT): Enables 14B-32B parameters models with complex reasoning, basic RAG, data pipeline execution, multi-stage summarization. Highly responsive on desktop workstations (Mac Studio / Nvidia GeForce RTX).",
2: "ENTERPRISE DEPLOYMENTS: Capable of running heavy 70B+ parameters sovereign engines or multiple concurrent agent pipelines. Replaces complex proprietary SaaS platforms completely with extreme performance."
};
const goalVerdicts: Record<GoalType, string> = {
writing: "PERFECTLY FEASIBLE: Writing assistance is extremely light on RAM. A standard 16GB office laptop can handle this effortlessly, outputting texts faster than human typing with zero cloud lag.",
rag: "HIGHLY PRACTICAL: Deep content classification and table mapping excel in dedicated local structures. No sensitive customer directories are ever sent across cloud channels.",
agents: "REVENUE WINNER: Drag-and-drop secure file indexing allows instant conversational searches of massive internal manuals. Keeps sensitive IP completely under your company lock and key."
};
interface TaskSpec {
model: string;
setup: string;
hardware: string;
cost: string;
}
const getTaskSpec = (goal: GoalType): TaskSpec => {
const specs: Record<GoalType, TaskSpec> = {
writing: {
model: "Llama-3.1-8B-Instruct (or Mistral-7B)",
setup: "LM Studio / Jan Desktop (GUI offline shells)",
hardware: "8GB-16GB RAM laptop or consumer PC",
cost: "$0.00 / Zero subscription forever"
},
rag: {
model: "Qwen-2.5-14B-Instruct-Q4 (or Llama-3-8B)",
setup: "AnythingLLM / Open WebUI Desktop GUI (Zero coding required)",
hardware: "16GB RAM laptop or light business machine",
cost: "$0.00 / Zero subscription forever"
},
agents: {
model: "Command-R-35B-Q4 (or Llama-3.1-8B-Instruct)",
setup: "AnythingLLM / PrivateGPT (Desktop Drag-and-Drop)",
hardware: "16GB-32GB standard office PC (Unified RAM)",
cost: "$0.00 / Zero subscription forever"
}
};
return specs[goal];
};
interface ActionStep {
num: number;
text: string;
}
const getActionSteps = (goal: GoalType): ActionStep[] => {
if (goal === 'writing') {
return [
{ num: 1, text: "Download & install <strong>LM Studio</strong> or <strong>Jan App</strong> on your current hardware." },
{ num: 2, text: "Search registry for <strong>llama-3.1-8b-instruct</strong> and download the 4-bit config weight (Q4_K_M)." },
{ num: 3, text: "You're ready! Start writing content safely offline with zero licensing or subscription stress!" }
];
} else if (goal === 'rag') {
return [
{ num: 1, text: "Download & install <strong>AnythingLLM Desktop</strong> or <strong>Jan Desktop</strong>." },
{ num: 2, text: "Launch the app, choose any small quantized model from the built-in library, and click download." },
{ num: 3, text: "Drag and drop your content folders or business contracts to automatically organize, search, or summarize them!" }
];
} else {
return [
{ num: 1, text: "Download & launch the free <strong>AnythingLLM Desktop</strong> program." },
{ num: 2, text: "Establish a localized workspace and import folder directories of PDF reports/Excel briefs." },
{ num: 3, text: "Query models securely offline. The vector database runs completely on disk with zero cloud lookups." }
];
}
};
interface Slide6HardwareMatrixProps {
selectedGoal: GoalType;
procureBudget: BudgetType;
onGoalChange: (goal: GoalType) => void;
onBudgetChange: (budget: BudgetType) => void;
}
export default function Slide6HardwareMatrix({
selectedGoal,
procureBudget,
onGoalChange,
onBudgetChange
}: Slide6HardwareMatrixProps) {
const [selectedHardwareRow, setSelectedHardwareRow] = useState<number>(0);
const [slide6Tab, setSlide6Tab] = useState<Slide6Tab>('tasks');
const handleElementClick = () => synth.playClick();
const handleTabChange = (tab: Slide6Tab) => {
handleElementClick();
setSlide6Tab(tab);
};
const handleHardwareSelect = (id: number) => {
handleElementClick();
setSelectedHardwareRow(id);
};
const handleGoalSelect = (goal: GoalType) => {
handleElementClick();
onGoalChange(goal);
};
const taskSpec = getTaskSpec(selectedGoal);
const actionSteps = getActionSteps(selectedGoal);
return (
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 items-stretch max-w-6xl mx-auto w-full text-left">
<div className="lg:col-span-5 flex flex-col justify-between">
<div>
<span className="text-emerald-500 font-mono text-xs font-bold uppercase tracking-wider mb-2">// DIRECTIVE ARCHITECTURE</span>
<h2 className="font-display font-bold text-2xl sm:text-3xl text-white tracking-tight uppercase leading-none mb-4">
Your Hardware Match
</h2>
<p className="text-slate-400 font-sans text-sm sm:text-base leading-relaxed mb-6">
Map local AI targets against your company assets. Standard office equipment already houses substantial computational power. Utilize our selector to plan your deployment.
</p>
<div className="flex bg-slate-950/80 border border-slate-800/80 rounded p-1 gap-1 mb-6 font-mono text-[10px]">
<button
type="button"
onClick={() => handleTabChange('tasks')}
className={`flex-1 py-2 px-3 rounded text-center transition-all duration-150 cursor-pointer font-bold ${
slide6Tab === 'tasks'
? 'bg-emerald-950/50 border border-emerald-500/30 text-emerald-400 text-glow'
: 'text-slate-500 hover:text-slate-350 border border-transparent'
}`}
>
USE CASES MATCHING
</button>
<button
type="button"
onClick={() => handleTabChange('hardware')}
className={`flex-1 py-2 px-3 rounded text-center transition-all duration-150 cursor-pointer font-bold ${
slide6Tab === 'hardware'
? 'bg-emerald-950/50 border border-emerald-500/30 text-emerald-400 text-glow'
: 'text-slate-500 hover:text-slate-350 border border-transparent'
}`}
>
💻 HARDWARE TIERS
</button>
</div>
</div>
{slide6Tab === 'hardware' ? (
<div className="bg-slate-950/40 border border-emerald-950/30 rounded-lg p-5 font-mono">
<div className="flex items-center gap-2 text-emerald-400 text-xs font-bold mb-2">
<Cpu className="w-4 h-4 text-emerald-400" />
<span>MAPPED SILICON COMPATIBILITY:</span>
</div>
<p className="text-[12px] leading-relaxed text-slate-300">
{hardwareDetails[selectedHardwareRow]}
</p>
</div>
) : (
<div className="bg-slate-950/40 border border-emerald-950/30 rounded-lg p-5 font-mono">
<div className="flex items-center gap-2 text-emerald-400 text-xs font-bold mb-2">
<Sparkles className="w-4 h-4 text-emerald-400" />
<span>SOVEREIGN VERDICT:</span>
</div>
<p className="text-[12px] leading-relaxed text-slate-300">
{goalVerdicts[selectedGoal]}
</p>
</div>
)}
</div>
<div className="lg:col-span-7 flex flex-col w-full">
<div className="bg-slate-950/60 border border-slate-800/80 rounded-xl p-5 sm:p-6 flex-1 flex flex-col justify-between relative overflow-hidden">
{slide6Tab === 'hardware' && (
<div className="flex flex-col gap-3">
<div className="flex justify-between items-center font-mono text-[10px] text-slate-400 mb-2">
<span>INTERACTIVE MEMORY SPEC MATRIX</span>
<span className="text-emerald-400 font-bold"> SELECT HARDWARE</span>
</div>
{hardwareRows.map((row) => (
<div
key={row.id}
onClick={() => handleHardwareSelect(row.id)}
className={`p-4 rounded-lg border transition-all duration-300 cursor-pointer flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 ${
selectedHardwareRow === row.id
? 'border-emerald-500 bg-emerald-950/25 shadow-[0_0_15px_rgba(16,185,129,0.15)]'
: 'border-slate-850 bg-slate-900/40 hover:border-slate-700 hover:bg-slate-900/80'
}`}
>
<div className="text-left">
<span className={`font-mono text-[9px] font-bold block mb-1 uppercase ${
selectedHardwareRow === row.id ? 'text-emerald-400' : 'text-slate-500'
}`}>
TIER_0{row.id + 1} // {selectedHardwareRow === row.id ? 'ACTIVE SPEC' : 'INACTIVE'}
</span>
<h3 className="font-display font-bold text-white text-base">
{row.tier}
</h3>
<p className="font-sans text-[11px] text-slate-400 mt-0.5">
<strong>Hardware:</strong> {row.hardware}
</p>
</div>
<div className="text-left sm:text-right shrink-0">
<span className="font-mono text-[10px] text-emerald-500 text-glow font-bold block">
{row.models}
</span>
<span className="font-sans text-[10px] text-slate-500 block">
{row.capacity}
</span>
</div>
</div>
))}
</div>
)}
{slide6Tab === 'tasks' && (
<div className="flex flex-col h-full justify-between">
<div className="flex justify-between items-center font-mono text-[10px] text-slate-400 mb-4">
<span>TASK TO LOCAL MODEL MATCHING BLUEPRINTS</span>
<span className="text-emerald-400 font-bold"> ONLINE PLANNER</span>
</div>
<div className="grid grid-cols-3 gap-2 mb-4 font-mono">
{[
{ id: 'writing' as GoalType, label: '✍ WRITING SUPPORT', desc: 'Content & copywriting' },
{ id: 'rag' as GoalType, label: '📄 DOC ANALYSIS', desc: 'Data parsing & extraction' },
{ id: 'agents' as GoalType, label: '🔍 FILE Q&A (RAG)', desc: 'Knowledge Base search' }
].map((tsk) => (
<button
key={tsk.id}
onClick={() => handleGoalSelect(tsk.id)}
className={`p-2.5 rounded border text-center cursor-pointer transition-all duration-200 flex flex-col items-center justify-center gap-1 ${
selectedGoal === tsk.id
? 'border-emerald-500 bg-emerald-950/25 text-emerald-400 font-bold shadow-[0_0_8px_rgba(16,185,129,0.1)]'
: 'border-slate-850 bg-slate-900/40 text-slate-400 hover:border-slate-700 hover:text-slate-200'
}`}
>
<span className="text-[10px] font-bold leading-none">{tsk.label}</span>
<span className="text-[7.5px] text-slate-500 leading-none">{tsk.desc}</span>
</button>
))}
</div>
<div className="bg-slate-900 border border-slate-850 rounded p-4 mb-4 grid grid-cols-1 md:grid-cols-2 gap-4 text-slate-200 text-xs font-mono">
<div className="flex flex-col gap-2">
<div>
<span className="text-[9px] text-slate-500 font-semibold block uppercase">TARGET MODEL WEIGHTS:</span>
<span className="text-emerald-400 font-bold text-sm">{taskSpec.model}</span>
</div>
<div>
<span className="text-[9px] text-slate-500 font-semibold block uppercase">PRACTICAL SETUP APPLICATION:</span>
<span className="text-white">{taskSpec.setup}</span>
</div>
</div>
<div className="flex flex-col gap-2 md:border-l md:border-slate-800 md:pl-4">
<div>
<span className="text-[9px] text-slate-500 font-semibold block uppercase">MINIMUM COMPUTER HARDWARE:</span>
<span className="text-white">{taskSpec.hardware}</span>
</div>
<div>
<span className="text-[9px] text-slate-500 font-semibold block uppercase">COST TAX:</span>
<span className="text-emerald-400 text-glow font-bold">{taskSpec.cost}</span>
</div>
</div>
</div>
<div className="bg-slate-950 rounded p-3 text-left font-mono border border-slate-850">
<span className="text-[8.5px] text-slate-500 font-bold block uppercase mb-1.5">// IMMEDIATE ACTION PLAN (FIRST STEPS):</span>
<div className="flex flex-col gap-1.5 text-[11px] text-slate-300">
{actionSteps.map((step) => (
<p key={step.num} className="flex gap-2">
<span className="text-emerald-400 font-bold">{step.num}.</span>
<span dangerouslySetInnerHTML={{ __html: step.text }} />
</p>
))}
</div>
</div>
</div>
)}
</div>
</div>
</div>
);
}
@@ -0,0 +1,210 @@
import { AlertTriangle, Terminal, Sparkles, ArrowRight } from 'lucide-react';
import { BudgetType, GoalType } from '../../types';
import { getHardwareProcureData } from '../../utils/hardwareData';
import { synth } from '../../utils/audioSynth';
interface Slide7BuyersGuideProps {
showToast: (msg: string) => void;
selectedGoal: GoalType;
procureBudget: BudgetType;
onGoalChange: (goal: GoalType) => void;
onBudgetChange: (budget: BudgetType) => void;
}
interface BudgetOption {
id: BudgetType;
label: string;
sub: string;
}
const budgetOptions: BudgetOption[] = [
{ id: 'existing', label: '💻 EXISTING ASSETS', sub: 'Zero Cost ($0)' },
{ id: 'budget', label: '⚡ LIGHT UPGRADE', sub: 'Under $1,500' },
{ id: 'pro', label: '🔥 PRO STUDIO', sub: '$2k - $4k' },
{ id: 'enterprise', label: '🏢 ENTERPRISE NODE', sub: 'Over $5k' }
];
export default function Slide7BuyersGuide({
showToast,
selectedGoal,
procureBudget,
onGoalChange,
onBudgetChange
}: Slide7BuyersGuideProps) {
const handleElementClick = () => synth.playClick();
const handleBudgetSelect = (budget: BudgetType) => {
handleElementClick();
onBudgetChange(budget);
};
const handleGoalSelect = (goal: GoalType) => {
handleElementClick();
onGoalChange(goal);
};
const spec = getHardwareProcureData(procureBudget, selectedGoal);
return (
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 items-stretch max-w-6xl mx-auto w-full text-left font-sans animate-fade-in">
<div className="lg:col-span-5 flex flex-col justify-between">
<div>
<span className="text-emerald-500 font-mono text-xs font-bold uppercase tracking-wider mb-2 block">// SPECIFICATION OPTIMIZER</span>
<h2 className="font-display font-bold text-2xl sm:text-3xl text-white tracking-tight uppercase leading-none mb-4">
Easy Setup & Hardware Guide
</h2>
<p className="text-slate-400 text-xs sm:text-sm leading-relaxed mb-5">
Buying or repurposing hardware is simple once you isolate your goals. Modern large models scale entirely based on **Memory Bandwidth** rather than CPU cores. Select your options below to see your optimal setup plan:
</p>
<div className="mb-4">
<label className="block text-slate-500 font-mono text-[9px] uppercase tracking-wider mb-2 font-bold">// 1. CHOOSE AVAILABLE BUDGET PROFILE</label>
<div className="grid grid-cols-2 gap-2 font-mono">
{budgetOptions.map((btn) => (
<button
key={btn.id}
type="button"
onClick={() => handleBudgetSelect(btn.id)}
className={`p-2.5 rounded border text-left transition-all duration-200 cursor-pointer ${
procureBudget === btn.id
? 'border-emerald-500 bg-emerald-950/20 text-emerald-400 font-bold shadow-[0_0_8px_rgba(16,185,129,0.1)]'
: 'border-slate-850 bg-slate-900/30 text-slate-400 hover:border-slate-750 hover:text-slate-200'
}`}
>
<span className="block text-[10px] tracking-tight">{btn.label}</span>
<span className={`block text-[8px] font-semibold ${procureBudget === btn.id ? 'text-emerald-500' : 'text-slate-500'}`}>{btn.sub}</span>
</button>
))}
</div>
</div>
<div className="mb-5">
<label className="block text-slate-500 font-mono text-[9px] uppercase tracking-wider mb-2 font-bold">// 2. CHOOSE PRIMARY BUSINESS VALUE INTENT</label>
<div className="flex flex-col gap-2 font-mono">
<button
type="button"
onClick={() => handleGoalSelect('writing')}
className={`p-3 rounded border text-left transition-all duration-150 cursor-pointer flex justify-between items-center ${
selectedGoal === 'writing'
? 'border-emerald-500 bg-emerald-950/25 text-emerald-400 font-bold'
: 'border-slate-850 bg-slate-900/30 text-slate-400 hover:border-slate-750 hover:text-slate-200'
}`}
>
<div>
<span className="block text-[10px] tracking-tight"> CONTENT ENGINE</span>
<span className="block font-sans text-[8.5px] font-normal text-slate-500 leading-none mt-0.5">Drafting, summarizing, code autocompletion</span>
</div>
<ArrowRight className={`w-3 h-3 shrink-0 ${selectedGoal === 'writing' ? 'text-emerald-400' : 'text-slate-600'}`} />
</button>
<button
type="button"
onClick={() => handleGoalSelect('rag')}
className={`p-3 rounded border text-left transition-all duration-150 cursor-pointer flex justify-between items-center ${
selectedGoal === 'rag'
? 'border-emerald-500 bg-emerald-950/25 text-emerald-400 font-bold'
: 'border-slate-850 bg-slate-900/30 text-slate-400 hover:border-slate-750 hover:text-slate-200'
}`}
>
<div>
<span className="block text-[10px] tracking-tight">🔍 FILE COGNITIVE INDEX (RAG)</span>
<span className="block font-sans text-[8.5px] font-normal text-slate-500 leading-none mt-0.5">Instant Q&A across deep manual archives / directories</span>
</div>
<ArrowRight className={`w-3 h-3 shrink-0 ${selectedGoal === 'rag' ? 'text-emerald-400' : 'text-slate-600'}`} />
</button>
<button
type="button"
onClick={() => handleGoalSelect('agents')}
className={`p-3 rounded border text-left transition-all duration-150 cursor-pointer flex justify-between items-center ${
selectedGoal === 'agents'
? 'border-emerald-500 bg-emerald-950/25 text-emerald-400 font-bold'
: 'border-slate-850 bg-slate-900/30 text-slate-400 hover:border-slate-750 hover:text-slate-200'
}`}
>
<div>
<span className="block text-[10px] tracking-tight">🤖 MULTI-AGENT SWARM PIPELINES</span>
<span className="block font-sans text-[8.5px] font-normal text-slate-500 leading-none mt-0.5">Host complex orchestrated background reasoning routines</span>
</div>
<ArrowRight className={`w-3 h-3 shrink-0 ${selectedGoal === 'agents' ? 'text-emerald-400' : 'text-slate-600'}`} />
</button>
</div>
</div>
</div>
<div className="bg-rose-950/15 border border-rose-900/25 p-4 rounded-lg text-slate-350 font-sans text-[11px] leading-relaxed flex gap-3">
<AlertTriangle className="w-5 h-5 text-rose-500 shrink-0 animate-pulse" />
<div>
<span className="font-mono text-[9.5px] font-bold text-rose-400 tracking-wider block uppercase mb-1">// CRITICAL BUYER SHIELD PROTOCOL:</span>
Do NOT buy multiple CPU-core servers expecting quick inference speeds. LLM read-phases are bound strictly by **Memory Bandwidth**. Prefer Apple Silicon (Unified Memory bus width &gt; 300GB/s) or discrete Nvidia RTX Series GPUs. CPU-only rendering will result in a 5x to 10x speed penalty.
</div>
</div>
</div>
<div className="lg:col-span-7 flex flex-col w-full font-sans">
<div className="bg-slate-950/60 border border-slate-800/80 rounded-xl p-5 sm:p-6 flex-1 flex flex-col justify-between relative overflow-hidden text-slate-200 font-mono">
<div className="flex justify-between items-center font-mono text-[10px] text-slate-400 mb-4 border-b border-slate-900 pb-3">
<span>SOVEREIGN HARDWARE DEPLOYMENT SPECIFICATION</span>
<span className="text-emerald-400 font-bold animate-pulse"> MODEL GENERATED</span>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4 text-left">
<div className="p-3 bg-slate-900/80 border border-slate-850 rounded">
<span className="text-[8.5px] text-slate-500 block font-semibold">// RECOMMENDED SILICON TYPE:</span>
<span className="text-white text-xs font-bold block mt-1 leading-normal font-sans">{spec.machineType}</span>
</div>
<div className="p-3 bg-slate-900/80 border border-slate-850 rounded">
<span className="text-[8.5px] text-slate-500 block font-semibold">// OPTIMAL CAPACITY & MEMORY:</span>
<span className="text-emerald-400 text-glow text-xs font-bold block mt-1 leading-normal font-sans">{spec.ramType}</span>
</div>
<div className="p-3 bg-slate-900/80 border border-slate-850 rounded">
<span className="text-[8.5px] text-slate-500 block font-semibold">// MINIMUM SYSTEM BUS SPEED:</span>
<span className="text-white text-xs block mt-1 leading-normal font-sans">{spec.bandWidth}</span>
</div>
<div className="p-3 bg-slate-900/80 border border-slate-850 rounded">
<span className="text-[8.5px] text-slate-500 block font-semibold">// TARGET QUANTIZED MODEL WEIGHTS:</span>
<span className="text-emerald-400 font-bold text-xs block mt-1 leading-normal font-sans">{spec.modelGoal}</span>
</div>
</div>
<div className="bg-slate-900 border border-slate-850 rounded p-4 mb-4 text-left font-mono">
<div className="flex items-center gap-1.5 text-emerald-450 text-[10px] font-bold mb-1.5 uppercase">
<Sparkles className="w-3.5 h-3.5 text-emerald-400" />
<span>PERFORMANCE CAPABILITY ESTIMATE:</span>
</div>
<p className="text-slate-300 text-xs font-sans leading-relaxed">
{spec.verdict}
</p>
</div>
<div className="bg-slate-950 p-4 rounded-lg border border-slate-850 mb-4 text-left text-xs">
<span className="text-[9px] text-slate-500 font-bold block uppercase mb-2 font-mono">// SOFTWARE STACK TO DEPLOY:</span>
<div className="flex gap-2 items-start text-slate-300 bg-slate-900/50 p-2.5 rounded border border-slate-850">
<Terminal className="w-4 h-4 text-emerald-400 shrink-0 mt-0.5" />
<div className="font-sans">
<strong className="text-white block text-[11px] mb-0.5 font-mono">// LAUNCH TOOL COMPANIONS</strong>
<p className="text-[10px] text-slate-400 leading-relaxed mb-1.5">
Download & initialize <span className="text-emerald-400 font-bold">{spec.setupTools}</span>.
</p>
<span className="text-[9.5px] text-slate-500 italic block">
{spec.purchaseTip}
</span>
</div>
</div>
</div>
<div className="bg-slate-900/40 p-3 rounded text-[9px] text-slate-500 flex justify-between items-center border border-slate-900 font-mono">
<span className="flex items-center gap-1"><span className="text-emerald-500"></span> SOURCE SPEC</span>
<span className="text-slate-700"></span>
<span className="flex items-center gap-1"><span className="text-emerald-500"></span> MAP TO GOALS</span>
<span className="text-slate-700"></span>
<span className="flex items-center gap-1"><span className="text-emerald-500"></span> BYPASS CPU TRAP</span>
<span className="text-slate-700"></span>
<span className="text-emerald-400 font-bold animate-pulse">// REQUISITION READY</span>
</div>
</div>
</div>
</div>
);
}
@@ -0,0 +1,219 @@
import { useState } from 'react';
import { GoalType, BudgetType } from '../../types';
import { synth } from '../../utils/audioSynth';
interface Slide8ROIProps {
selectedGoal: GoalType;
procureBudget: BudgetType;
showToast: (msg: string) => void;
}
export default function Slide8ROI({ selectedGoal, procureBudget, showToast }: Slide8ROIProps) {
const [employees, setEmployees] = useState<number>(120);
const [monthlySaaS, setMonthlySaaS] = useState<number>(35);
const [setupCosts, setSetupCosts] = useState<number>(6500);
const handleElementClick = () => synth.playClick();
const handleGoalCostApply = () => {
handleElementClick();
const goalCostMap: Record<GoalType, number> = { writing: 0, rag: 1500, agents: 3500 };
const targetCost = goalCostMap[selectedGoal] ?? 3500;
setSetupCosts(targetCost);
showToast(`Applied ${selectedGoal.toUpperCase()} goal recommendation: $${targetCost.toLocaleString()}`);
};
const handleBudgetCostApply = () => {
handleElementClick();
const bgtCostMap: Record<BudgetType, number> = { existing: 0, budget: 1500, pro: 3500, enterprise: 12500 };
const targetCost = bgtCostMap[procureBudget] ?? 1500;
setSetupCosts(targetCost);
showToast(`Applied ${procureBudget.toUpperCase()} specification plan: $${targetCost.toLocaleString()}`);
};
const cloudMonthlyCost = employees * monthlySaaS;
const cloudAnnualCost = cloudMonthlyCost * 12;
const localAnnualOperatingSalaryFraction = 1200;
const firstYearSavings = Math.max(0, cloudAnnualCost - setupCosts - localAnnualOperatingSalaryFraction);
const threeYearSavings = Math.max(0, (cloudAnnualCost * 3) - setupCosts - (localAnnualOperatingSalaryFraction * 3));
const breakEvenMonths = cloudMonthlyCost > 0 ? (setupCosts / cloudMonthlyCost).toFixed(1) : "0.0";
const getGoalCost = () => {
const goalCostMap: Record<GoalType, number> = { writing: 0, rag: 1500, agents: 3500 };
return goalCostMap[selectedGoal];
};
const getBudgetCost = () => {
const bgtCostMap: Record<BudgetType, number> = { existing: 0, budget: 1500, pro: 3500, enterprise: 12500 };
return bgtCostMap[procureBudget];
};
const getGoalLabel = () => {
if (selectedGoal === 'writing') return "✍ Writing Support";
if (selectedGoal === 'rag') return "📄 Doc Analysis";
return "🔍 File Q&A (RAG)";
};
const getBudgetLabel = () => {
if (procureBudget === 'existing') return "💻 Existing Machine";
if (procureBudget === 'budget') return "⚡ Light Upgrade";
if (procureBudget === 'pro') return "🔥 Pro Studio Setup";
return "🏢 Enterprise Rack";
};
return (
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 items-center max-w-6xl mx-auto w-full">
<div className="lg:col-span-5 flex flex-col justify-center text-left">
<span className="text-emerald-500 font-mono text-xs font-bold uppercase tracking-wider mb-2">// COST BREAKDOWN</span>
<h2 className="font-display font-bold text-2xl sm:text-3xl text-white tracking-tight uppercase leading-none mb-4">
Zero-Cost Lifetime ROI
</h2>
<p className="text-slate-400 font-sans text-sm sm:text-base leading-relaxed mb-6">
SaaS applications levy a lifetime licensing tax. Leverage your existing compute hardware assets to entirely sever monthly billing spikes and dynamically scale model invocations with absolute zero marginal cost.
</p>
<div className="bg-slate-950/50 border border-slate-800/80 rounded-xl p-5 font-mono text-[11px] text-slate-350 flex flex-col gap-2.5">
<div className="flex items-center justify-between border-b border-slate-850 pb-2 text-[10px] text-slate-500">
<span>SOVEREIGN EFFICIENCY REPORT</span>
<span className="text-emerald-400">STATUS: GOLD_RATED</span>
</div>
<div className="flex justify-between">
<span>ESTIMATED BREAK-EVEN:</span>
<span className="text-emerald-400 text-glow font-bold">{breakEvenMonths} Months</span>
</div>
<div className="flex justify-between">
<span>FIRST YEAR SAVINGS:</span>
<span className="text-emerald-400 font-bold">${firstYearSavings.toLocaleString()}</span>
</div>
<div className="flex justify-between">
<span>3-YEAR LIFETIME SAVINGS:</span>
<span className="text-emerald-400 text-glow font-bold">${threeYearSavings.toLocaleString()}</span>
</div>
</div>
</div>
<div className="lg:col-span-7 flex flex-col w-full">
<div className="bg-slate-950/60 border border-slate-800/80 rounded-xl p-6 text-left flex flex-col gap-5">
<div className="flex justify-between items-center font-mono text-[10px] text-slate-400">
<span>LIVE RETURN-ON-INVESTMENT CALCULATOR</span>
<span className="text-emerald-400 font-bold"> DYNAMIC</span>
</div>
<div className="flex flex-col gap-1.5">
<div className="flex items-center justify-between font-mono text-[11px]">
<span className="text-slate-300">COMPANY SIZE (STAFF/USERS):</span>
<span className="text-white font-bold">{employees} employees</span>
</div>
<input
type="range"
min="10"
max="500"
step="10"
value={employees}
onChange={(e) => { handleElementClick(); setEmployees(Number(e.target.value)); }}
className="w-full h-1 bg-slate-900 rounded-lg appearance-none cursor-pointer accent-emerald-500"
/>
</div>
<div className="flex flex-col gap-1.5">
<div className="flex items-center justify-between font-mono text-[11px]">
<span className="text-slate-300">ESTIMATED MONTHLY CLOUD SAAS COST (PER USER):</span>
<span className="text-white font-bold">${monthlySaaS} / user / mo</span>
</div>
<input
type="range"
min="10"
max="100"
step="5"
value={monthlySaaS}
onChange={(e) => { handleElementClick(); setMonthlySaaS(Number(e.target.value)); }}
className="w-full h-1 bg-slate-900 rounded-lg appearance-none cursor-pointer accent-emerald-500"
/>
</div>
<div className="bg-slate-900/60 p-3 rounded-lg border border-slate-800/80 flex flex-col gap-3 font-sans">
<div className="flex justify-between items-center text-[10px] font-mono font-bold text-slate-400 uppercase tracking-tight">
<span>🔌 SYNC INFRASTRUCTURE COST TO DECISION PATH</span>
<span className="text-emerald-400 font-black tracking-normal animate-pulse"> SELECT TO APPLY</span>
</div>
<div className="grid grid-cols-2 gap-2.5">
<button
type="button"
onClick={handleGoalCostApply}
className="p-2.5 rounded border border-slate-850 bg-slate-950/40 text-left hover:border-emerald-500/50 hover:bg-slate-900/80 hover:shadow-[0_0_12px_rgba(16,185,129,0.06)] transition-all duration-200 cursor-pointer flex flex-col justify-between"
>
<div>
<span className="text-[8px] text-slate-500 font-mono tracking-wider font-bold block uppercase mb-1">// S6 ACTIVE GOAL</span>
<span className="text-[11px] text-white font-bold leading-none font-sans block truncate">
{getGoalLabel()}
</span>
</div>
<span className="text-[10px] text-emerald-400 font-bold block mt-2 font-mono">
Use Rec: ${getGoalCost().toLocaleString()}
</span>
</button>
<button
type="button"
onClick={handleBudgetCostApply}
className="p-2.5 rounded border border-slate-850 bg-slate-950/40 text-left hover:border-emerald-500/50 hover:bg-slate-900/80 hover:shadow-[0_0_12px_rgba(16,185,129,0.06)] transition-all duration-200 cursor-pointer flex flex-col justify-between"
>
<div>
<span className="text-[8px] text-slate-500 font-mono tracking-wider font-bold block uppercase mb-1">// S7 SPECIFICATION</span>
<span className="text-[11px] text-white font-bold leading-none font-sans block truncate">
{getBudgetLabel()}
</span>
</div>
<span className="text-[10px] text-emerald-450 font-bold block mt-2 font-mono">
Spec Cost: ${getBudgetCost().toLocaleString()}
</span>
</button>
</div>
</div>
<div className="flex flex-col gap-1.5">
<div className="flex items-center justify-between font-mono text-[11px]">
<span className="text-slate-300">ONE-OFF INFRASTRUCTURE UPGRADE INVESTMENT:</span>
<span className="text-white font-bold">${setupCosts.toLocaleString()}</span>
</div>
<input
type="range"
min="0"
max="30000"
step="500"
value={setupCosts}
onChange={(e) => { handleElementClick(); setSetupCosts(Number(e.target.value)); }}
className="w-full h-1 bg-slate-900 rounded-lg appearance-none cursor-pointer accent-emerald-500"
/>
</div>
<div className="grid grid-cols-2 gap-4 mt-2">
<div className="p-4 rounded-lg bg-slate-905 border border-slate-850 flex flex-col justify-between">
<div>
<span className="font-mono text-[9px] text-slate-500 block uppercase mb-1">Yearly Cloud Cost (Hemorrhaging)</span>
<span className="font-display font-extrabold text-lg sm:text-xl text-rose-450">${cloudAnnualCost.toLocaleString()}</span>
</div>
<div className="h-2 w-full bg-slate-950 rounded-full overflow-hidden mt-3">
<div className="h-full bg-rose-500 w-full" />
</div>
</div>
<div className="p-4 rounded-lg bg-emerald-950/20 border border-emerald-900/35 flex flex-col justify-between">
<div>
<span className="font-mono text-[9px] text-emerald-450 block uppercase mb-1">Local Sovereign Cost (First Year Upgrade)</span>
<span className="font-display font-extrabold text-lg sm:text-xl text-emerald-450">${(setupCosts + 1200).toLocaleString()}</span>
</div>
<div className="h-2 w-full bg-slate-950 rounded-full overflow-hidden mt-3">
<div
className="h-full bg-emerald-500 transition-all duration-300"
style={{ width: `${Math.min(100, ((setupCosts + 1200) / cloudAnnualCost) * 100)}%` }}
/>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
@@ -0,0 +1,196 @@
import { useState, useRef, FormEvent } from 'react';
import { motion } from 'motion/react';
import { WifiOff, Lock } from 'lucide-react';
import { LogSequence } from '../../types';
import { synth } from '../../utils/audioSynth';
interface Slide9OfflineDemoProps {
showToast: (msg: string) => void;
}
export default function Slide9OfflineDemo({ showToast }: Slide9OfflineDemoProps) {
const [isDisconnected, setIsDisconnected] = useState<boolean>(false);
const [demoStep, setDemoStep] = useState<number>(0);
const [demoLogs, setDemoLogs] = useState<string[]>([]);
const [demoPrompt, setDemoPrompt] = useState<string>("");
const [demoResponse, setDemoResponse] = useState<string>("");
const [demoPending, setDemoPending] = useState<boolean>(false);
const demoLogTimerRef = useRef<NodeJS.Timeout[]>([]);
const handleSeverConnection = () => {
synth.playDisconnect();
setIsDisconnected(true);
setDemoStep(1);
setDemoLogs([]);
setDemoResponse("");
setDemoPrompt("");
demoLogTimerRef.current.forEach(t => clearTimeout(t));
demoLogTimerRef.current = [];
const logSequence: LogSequence[] = [
{ text: "⚡ [SEVER_INITIATED] Intercepting all global socket calls...", delay: 200 },
{ text: "🔴 [PING_FAILED] api.openai.com - Request timeout (Route blocked)", delay: 800 },
{ text: "🔴 [CONN_DEAD] gateway.anthropic.com - Destination unreachable", delay: 1400 },
{ text: "🔒 [OFFLINE_ENFORCED] Firewall rules securely locked. Outbound data leakage risk: 0.00%", delay: 2000 },
{ text: "📦 [DEPLOYING] Mount local weights: 'llama-3-8b-instruct.Q4_K_M.gguf'", delay: 2600 },
{ text: "🚀 [CPU_AVX2] GPU acceleration mapped to RTX VRAM Core.", delay: 3200 },
{ text: "✅ [Sovereign-Llama3-v1] Online in 100% disconnected sandbox environment.", delay: 3800 }
];
logSequence.forEach((seq) => {
const timer = setTimeout(() => {
setDemoLogs((prev) => [...prev, seq.text]);
synth.playBlip();
if (seq.text.startsWith('✅')) {
setDemoStep(2);
}
}, seq.delay);
demoLogTimerRef.current.push(timer);
});
};
const submitDemoPrompt = (e: FormEvent) => {
e.preventDefault();
if (!demoPrompt.trim() || demoPending) return;
synth.playClick();
setDemoPending(true);
setDemoResponse("");
const mockAiResponses: { [key: string]: string } = {
default: "SYSTEM RESPONSE // SOVEREIGN ENGINE:\n\nInput processed completely on-device in 143ms.\nResult: Secure compliance extraction verified. Ready for download. Zero bits sent beyond localhost.",
analysts: "LOCAL_ANALYSIS //\nWe ran sentiment scoring on the structured CSV feed. Standard Deviances: \n- Positivity: 84.1%\n- Risk Alert: Trace detected on Cloud API usage. Highly recommend immediate on-site fallback protocol.",
extract: "EXTRACTED SCHEMA:\n{\n 'transaction_id': 'TX90812',\n 'sovereign_rating': '10.0',\n 'cost_per_token': '$0.000000000'\n}"
};
setTimeout(() => {
const p = demoPrompt.toLowerCase();
let response = mockAiResponses.default;
if (p.includes('analyst') || p.includes('score') || p.includes('sentiment')) {
response = mockAiResponses.analysts;
} else if (p.includes('schema') || p.includes('json') || p.includes('extract')) {
response = mockAiResponses.extract;
}
setDemoResponse(response);
setDemoPending(false);
synth.playBlip();
}, 1100);
};
const handleReconnect = () => {
synth.playClick();
setIsDisconnected(false);
setDemoStep(0);
};
return (
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 items-center max-w-6xl mx-auto w-full">
<div className="lg:col-span-4 flex flex-col justify-center text-left">
<span className="text-emerald-500 font-mono text-xs font-bold uppercase tracking-wider mb-2">// SOVEREIGN DISCONNECT</span>
<h2 className="font-display font-bold text-2xl sm:text-3xl text-white tracking-tight uppercase leading-none mb-4">
Live Offline Walkthrough
</h2>
<p className="text-slate-400 font-sans text-sm sm:text-base leading-relaxed mb-6">
Witness absolute independence in motion. Flip the sovereign kill-switch to isolate your computing workspace and verify local cognitive offline processing in high-fidelity.
</p>
<div className="hidden lg:flex items-center gap-2 border border-slate-800/80 rounded px-3 py-1.5 bg-slate-900/50 text-[10px] font-mono text-slate-500">
<Lock className="w-3.5 h-3.5 text-emerald-400 shrink-0 animate-pulse" />
<span>Isolating terminal loops from network cards fully.</span>
</div>
</div>
<div className="lg:col-span-8 flex flex-col w-full">
<div className="bg-slate-950/60 border border-slate-800/80 rounded-xl p-5 sm:p-6 text-left flex flex-col gap-4">
{!isDisconnected ? (
<div className="flex flex-col items-center justify-center py-10 text-center">
<WifiOff className="w-16 h-16 text-emerald-500/30 animate-pulse mb-6" />
<h3 className="font-display font-bold text-lg text-white uppercase mb-2">OFF-GRID CONNECTION SANDBOX</h3>
<p className="text-slate-400 text-xs font-sans max-w-md mb-8">
Initiate off-grid mode to sever connection mapping hooks and activate offline model simulations on your local VRAM nodes.
</p>
<button
onClick={handleSeverConnection}
className="px-6 py-3 rounded bg-emerald-500 text-slate-950 font-mono text-xs font-black uppercase tracking-wider border border-emerald-400 hover:shadow-[0_0_20px_rgba(16,185,129,0.35)] cursor-pointer transition-all duration-300"
>
ACTIVATE OFF-GRID INTERRUPT
</button>
</div>
) : (
<div className="flex flex-col gap-4 h-full">
<div className="flex items-center justify-between border-b border-slate-800 pb-2">
<div className="flex items-center gap-2 text-[10px] font-mono font-bold text-emerald-400">
<span className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse-emerald" />
<span>OFF-GRID SANDBOX ENVIRONMENT ACTIVE</span>
</div>
<button
onClick={handleReconnect}
className="font-mono text-[9px] text-slate-500 hover:text-slate-350 hover:underline"
>
[RECONNECT NETWORK]
</button>
</div>
<div className="bg-slate-900 rounded p-3 font-mono text-[10px] text-slate-300 h-32 overflow-y-auto custom-scrollbar flex flex-col gap-1.5 border border-slate-850">
{demoLogs.map((log, idx) => (
<p key={idx} className={log.includes('Failed') || log.includes('Dead') ? 'text-rose-450 font-bold' : log.includes('Sovereign') ? 'text-emerald-400 font-bold' : ''}>
{log}
</p>
))}
{demoStep === 1 && (
<div className="flex items-center gap-2 text-slate-500">
<span className="w-1.5 h-1.5 rounded-full bg-slate-500 animate-ping" />
<span>Severing network nodes...</span>
</div>
)}
</div>
{demoStep === 2 && (
<motion.form
initial={{ opacity: 0, y: 5 }}
animate={{ opacity: 1, y: 0 }}
onSubmit={submitDemoPrompt}
className="flex flex-col gap-3 font-mono"
>
<div className="flex flex-col gap-1">
<label className="text-[9px] text-slate-500 uppercase">Test Sovereign Reasoning Invocations:</label>
<div className="flex gap-2">
<input
type="text"
value={demoPrompt}
onChange={(e) => setDemoPrompt(e.target.value)}
placeholder="Try prompt e.g.: 'Run Sentiment Score Matrix' or 'Extract JSON Schema'..."
className="flex-1 bg-slate-900 border border-slate-800 rounded px-3 py-2 text-xs text-white focus:outline-none focus:border-emerald-500"
/>
<button
type="submit"
disabled={demoPending || !demoPrompt.trim()}
className="px-4 py-2 bg-emerald-500 text-slate-950 rounded font-black text-xs uppercase cursor-pointer hover:bg-emerald-400 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
>
{demoPending ? 'RUNNING...' : 'SUBMIT'}
</button>
</div>
</div>
{(demoPending || demoResponse) && (
<div className="bg-slate-950 rounded border border-slate-850 p-3 h-28 overflow-y-auto custom-scrollbar font-mono text-[10px]">
{demoPending ? (
<div className="flex items-center gap-2 text-slate-500">
<div className="w-3 h-3 border border-t-emerald-500 border-r-transparent rounded-full animate-spin" />
<span>Invoking local model weights... SEC Compliance sandbox isolation 100% verified</span>
</div>
) : (
<pre className="text-emerald-400 break-words whitespace-pre-wrap">{demoResponse}</pre>
)}
</div>
)}
</motion.form>
)}
</div>
)}
</div>
</div>
</div>
);
}
+74
View File
@@ -0,0 +1,74 @@
import { Slide } from '../types';
export const SLIDES: Slide[] = [
{
id: 1,
title: "The Sovereign Business Engine",
subtitle: "Unlock Secure, Zero-Cost Local AI for Algarve Entrepreneurs, Nomads & Content Creators",
category: "INTRODUCTION"
},
{
id: 2,
title: "The Cloud Expense Trap",
points: [
"Data Leak Risks (Training on your client IP)",
"Unfair Subscriptions (A tax on every seat)",
"Sketchy Beach & Cafe Wi-Fi Downtime"
],
category: "RISK ANALYSIS"
},
{
id: 3,
title: "Your Private AI Workspace",
points: [
"Open-Source Brains (Free from big-tech license keys)",
"Visual Desktop Apps (Simple point-and-click layout)",
"100% Secure Offline Running (Zero data leaves your laptop)"
],
category: "ARCHITECTURE"
},
{
id: 4,
title: "AI Compression: Smart Scaling",
content: "Analogy: Premium high-end photo vs. optimized web graphic. Compression slashes memory needs by 75% so you can run powerful models directly on a normal laptop with no loss in logic.",
category: "PERFORMANCE OPTIMIZATION"
},
{
id: 5,
title: "Manual Overhead vs Smart Workflows",
points: [
"Stop playing chat ping-pong with slow prompts",
"Organize website posts, formatting, & emails instantly",
"Direct Clipboard-to-Excel / Content Management integrations"
],
category: "WORKFLOW AUTOMATION"
},
{
id: 6,
title: "Your Hardware Match",
points: [
"Standard Laptops: 16GB RAM (Excellent baseline)",
"Sweet Spot: 32GB-48GB RAM (Creative powerhouses)",
"Ultimate Studio: 64GB+ RAM (Complete cloud replacement)"
],
category: "HARDWARE MATRICES"
},
{
id: 7,
title: "Easy Setup & Hardware Guide",
subtitle: "Exactly what to buy or repurpose to replace expensive monthly software bills",
category: "BUYER'S GUIDE"
},
{
id: 8,
title: "Zero-Cost Lifetime ROI",
content: "Repurpose machines you already own, cut recurring monthly subscription spikes, and scale output to infinity for zero extra cost.",
category: "FINANCIAL FREEDOM"
},
{
id: 9,
title: "Live Offline Walkthrough",
content: "Pulling the internet plug. Absolute independence in action right here, right now.",
category: "LIVE DEMONSTRATION"
}
];
+72
View File
@@ -0,0 +1,72 @@
@import "tailwindcss";
@import url('https://fonts.googleapis.com/css2?family=Inter:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&family=JetBrains+Mono:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&family=Space+Grotesk:wght@300;400;500;600;700&display=swap');
@theme {
--font-sans: "Inter", sans-serif;
--font-mono: "JetBrains Mono", monospace;
--font-display: "Space Grotesk", sans-serif;
}
@layer utilities {
.cyber-grid {
background-size: 40px 40px;
background-image:
linear-gradient(to right, rgba(16, 185, 129, 0.04) 1px, transparent 1px),
linear-gradient(to bottom, rgba(16, 185, 129, 0.04) 1px, transparent 1px);
}
.cyber-glow {
box-shadow: 0 0 15px rgba(16, 185, 129, 0.15);
}
.cyber-glow-strong {
box-shadow: 0 0 25px rgba(16, 185, 129, 0.35);
}
.text-glow {
text-shadow: 0 0 8px rgba(16, 185, 129, 0.5);
}
.custom-scrollbar::-webkit-scrollbar {
width: 6px;
height: 6px;
}
.custom-scrollbar::-webkit-scrollbar-track {
background: transparent;
}
.custom-scrollbar::-webkit-scrollbar-thumb {
background: rgba(16, 185, 129, 0.2);
border-radius: 3px;
}
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
background: rgba(16, 185, 129, 0.4);
}
}
/* Scanline and flicker animations */
@keyframes cyber-scanline {
0% { transform: translateY(-100%); }
100% { transform: translateY(100%); }
}
.scanline::after {
content: " ";
display: block;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.25) 50%), linear-gradient(90deg, rgba(255, 0, 0, 0.06), rgba(0, 255, 0, 0.02), rgba(0, 0, 255, 0.06));
z-index: 2;
background-size: 100% 2px, 3px 100%;
pointer-events: none;
}
@keyframes pulse-emerald {
0%, 100% { opacity: 0.3; }
50% { opacity: 1; }
}
.animate-pulse-emerald {
animation: pulse-emerald 2s infinite;
}
+10
View File
@@ -0,0 +1,10 @@
import {StrictMode} from 'react';
import {createRoot} from 'react-dom/client';
import App from './App.tsx';
import './index.css';
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
);
+40
View File
@@ -0,0 +1,40 @@
// ==========================================
// TYPE DEFINITIONS
// ==========================================
export interface Slide {
id: number;
title: string;
subtitle?: string;
points?: string[];
content?: string;
category: string;
}
export interface ProcurementSpec {
machineType: string;
ramType: string;
bandWidth: string;
modelGoal: string;
verdict: string;
setupTools: string;
purchaseTip: string;
}
export type BudgetType = 'existing' | 'budget' | 'pro' | 'enterprise';
export type GoalType = 'writing' | 'rag' | 'agents';
export type QuantLevel = 'FP16' | 'Q8_0' | 'Q4_K_M' | 'Q2_K';
export type Slide6Tab = 'hardware' | 'tasks';
export interface ParsedData {
id: string;
name: string;
age: string;
region: string;
status: string;
}
export interface LogSequence {
text: string;
delay: number;
}
@@ -0,0 +1,145 @@
// ==========================================
// AUDIO SYNTHESIZER (Web Audio API)
// ==========================================
class CyberSynth {
private ctx: AudioContext | null = null;
public enabled: boolean = false;
private init() {
if (!this.ctx) {
this.ctx = new (window.AudioContext || (window as any).webkitAudioContext)();
}
}
public playClick() {
if (!this.enabled) return;
try {
this.init();
if (!this.ctx) return;
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.connect(gain);
gain.connect(this.ctx.destination);
osc.type = 'sine';
osc.frequency.setValueAtTime(880, this.ctx.currentTime);
osc.frequency.exponentialRampToValueAtTime(120, this.ctx.currentTime + 0.08);
gain.gain.setValueAtTime(0.08, this.ctx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.08);
osc.start();
osc.stop(this.ctx.currentTime + 0.08);
} catch (e) {
console.warn("Synth audio context failed: ", e);
}
}
public playBlip() {
if (!this.enabled) return;
try {
this.init();
if (!this.ctx) return;
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.connect(gain);
gain.connect(this.ctx.destination);
osc.type = 'triangle';
osc.frequency.setValueAtTime(1400, this.ctx.currentTime);
osc.frequency.setValueAtTime(1800, this.ctx.currentTime + 0.03);
gain.gain.setValueAtTime(0.04, this.ctx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.06);
osc.start();
osc.stop(this.ctx.currentTime + 0.06);
} catch (e) {
// Ignored
}
}
public playError() {
if (!this.enabled) return;
try {
this.init();
if (!this.ctx) return;
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.connect(gain);
gain.connect(this.ctx.destination);
osc.type = 'sawtooth';
osc.frequency.setValueAtTime(120, this.ctx.currentTime);
osc.frequency.linearRampToValueAtTime(80, this.ctx.currentTime + 0.15);
gain.gain.setValueAtTime(0.1, this.ctx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.15);
osc.start();
osc.stop(this.ctx.currentTime + 0.15);
} catch (e) {
// Ignored
}
}
public playSlideChange() {
if (!this.enabled) return;
try {
this.init();
if (!this.ctx) return;
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.connect(gain);
gain.connect(this.ctx.destination);
osc.type = 'sine';
osc.frequency.setValueAtTime(440, this.ctx.currentTime);
osc.frequency.exponentialRampToValueAtTime(660, this.ctx.currentTime + 0.12);
gain.gain.setValueAtTime(0.06, this.ctx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.12);
osc.start();
osc.stop(this.ctx.currentTime + 0.12);
} catch (e) {
// Ignored
}
}
public playDisconnect() {
if (!this.enabled) return;
try {
this.init();
if (!this.ctx) return;
const osc1 = this.ctx.createOscillator();
const osc2 = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc1.connect(gain);
osc2.connect(gain);
gain.connect(this.ctx.destination);
osc1.type = 'triangle';
osc1.frequency.setValueAtTime(300, this.ctx.currentTime);
osc1.frequency.linearRampToValueAtTime(30, this.ctx.currentTime + 0.8);
osc2.type = 'sawtooth';
osc2.frequency.setValueAtTime(295, this.ctx.currentTime);
osc2.frequency.linearRampToValueAtTime(25, this.ctx.currentTime + 0.8);
gain.gain.setValueAtTime(0.12, this.ctx.currentTime);
gain.gain.linearRampToValueAtTime(0.001, this.ctx.currentTime + 0.8);
osc1.start();
osc2.start();
osc1.stop(this.ctx.currentTime + 0.8);
osc2.stop(this.ctx.currentTime + 0.8);
} catch (e) {
// Ignored
}
}
}
export const synth = new CyberSynth();
@@ -0,0 +1,114 @@
// ==========================================
// HARDWARE RECOMMENDATION ENGINE DATA
// ==========================================
import { ProcurementSpec, BudgetType, GoalType } from '../types';
export const getHardwareProcureData = (budget: BudgetType, goal: GoalType): ProcurementSpec => {
if (budget === 'existing') {
if (goal === 'writing') {
return {
machineType: "Standard Office Laptop (Apple MacBook Air or standard business PC)",
ramType: "8GB - 16GB RAM (Standard System RAM Share)",
bandWidth: "80 GB/s to 150 GB/s (System bottleneck)",
modelGoal: "Llama-3-8B-Instruct (Q4) or lightweight content models",
verdict: "FEASIBLE AT ZERO COST: Run right now! Use your regular machine. You'll get 15-20 words/sec. Perfect for drafting emails, creating social posts, or polishing website copies on a sunny terrace in Faro.",
setupTools: "LM Studio Desktop App (Simple offline chat app) or Jan Desktop",
purchaseTip: "Tip: Shut down heavy browser tabs or video call software to free up system memory before starting your local writing session."
};
} else if (goal === 'rag') {
return {
machineType: "High-end corporate laptop or office PC with 16GB-32GB RAM",
ramType: "16GB - 32GB RAM (DDR4/DDR5 system memory)",
bandWidth: "125 GB/s standard dual-channel memory",
modelGoal: "Qwen-2.5-7B or Mistral-7B-Instruct (Q4 quantized weights)",
verdict: "PRACTICAL BUT CAUTIOUS: Local secure search index via AnythingLLM works beautifully, but parsing long folders of business PDFs will take 2-4 seconds per page on a standard processor.",
setupTools: "AnythingLLM Desktop (runs secure built-in local vector storage on your system disk with zero code)",
purchaseTip: "Tip: Import files in modest batches rather than drag-and-dropping 100 giant PDFs simultaneously to prevent standard system lag."
};
} else {
return {
machineType: "Premium creator or executive device (minimum 32GB memory)",
ramType: "32GB RAM dual-channel speed configuration",
bandWidth: "150 GB/s to 200 GB/s standard speed",
modelGoal: "Llama-3-8B-Instruct (Q4) or Qwen-2.5-14B (Q4 Quantized)",
verdict: "LIMITED CPU SPEED: Multi-agent automation loops run slow on standard processors. A complex, multi-step workflow could take 10-15 seconds to execute complete sequences.",
setupTools: "AnythingLLM Multi-Agent workspace (drag-and-drop automated flows, no code required)",
purchaseTip: "Tip: For multi-step tasks, select ultra-compact models like Llama-3-3B to preserve instant typing response."
};
}
} else if (budget === 'budget') {
if (goal === 'writing') {
return {
machineType: "Mid-Range Creator Laptop or Custom Workstation with Nvidia Graphics Card",
ramType: "32GB System RAM + 12GB/16GB VRAM on graphics board",
bandWidth: ">300 GB/s VRAM speed on graphics memory",
modelGoal: "Llama-3-8B (uncompressed) or Qwen-2.5-14B (high-fidelity)",
verdict: "EXTREME SPEED: You will generate 50-70 words per second. Faster than standard cloud APIs. Unlimited writing or translations with zero delay while enjoying Albufeira beach views.",
setupTools: "LM Studio / Jan desktop app (maps directly to your graphics hardware automatically)",
purchaseTip: "Tip: Look for high-performance laptops with an Nvidia Geforce RTX 4060 or 4070 (minimum 12GB memory) for peak content writing speed."
};
} else if (goal === 'rag') {
return {
machineType: "Custom Business Desktop PC with Nvidia GeForce RTX 4070 Ti Super",
ramType: "32GB DDR5 + 16GB Dedicated Graphics VRAM",
bandWidth: "504 GB/s dedicated graphics bus bandwidth",
modelGoal: "Command-R 35B (Q3 compressed) or Llama-3.1-8B-Instruct (high-fidelity)",
verdict: "HIGH CAPACITY: Powerful 35B parameter models run seamlessly on-device. The 16GB graphics card holds entire business directories or marketing templates for instant secure lookup.",
setupTools: "AnythingLLM Desktop mapped to Ollama engine backing graphics acceleration (Zero Code!)",
purchaseTip: "Tip: Choose the 'Ti Super' variant specifically, as standard cards carry smaller VRAM buffers (12GB) which limit local model sizes."
};
} else {
return {
machineType: "Nvidia RTX 4080 (16GB VRAM) or RTX 4070 Super Workstation",
ramType: "64GB DDR5 System RAM + 16GB high-bandwidth graphics VRAM",
bandWidth: "716 GB/s extreme graphics memory speed",
modelGoal: "Qwen-2.5-14B-Instruct or Llama-3-8B-Instruct (runs fully offloaded to graphics memory)",
verdict: "ENTREPRENEUR SWEET SPOT: Outstanding automation speeds. Runs local action-assistants rapidly, turning multi-step website work or translation reviews into split-second tasks.",
setupTools: "AnythingLLM Desktop with Multi-Agent features (100% visual point-and-click setup)",
purchaseTip: "Tip: Look for desktop towers with good ventilation. Graphics cards will run at full capacity during intense marketing or content automation runs."
};
}
} else if (budget === 'pro') {
if (goal === 'writing') {
return {
machineType: "Apple Mac Studio (M3 Max, 128GB Unified Memory)",
ramType: "128GB Unified ultra-speed System Memory",
bandWidth: "400 GB/s high bandwidth unified architecture",
modelGoal: "Llama-3-70B-Instruct (Q4) or Qwen-2.5-32B (high-fidelity)",
verdict: "TOP COGNITIVE RATING: Write complex content reports, marketing plans, and legal briefs using state-of-the-art 70B parameter models at ~25 words/second with ultimate security.",
setupTools: "Open WebUI Desktop interface locally running on your Mac without code",
purchaseTip: "Tip: Mac Studio unified memory is shared between active screen displays and model layers. Leave 16GB margin for OS overhead."
};
} else if (goal === 'rag') {
return {
machineType: "Apple Mac Studio (128GB Memory) or Pro Workstation with RTX 4090 (24GB)",
ramType: "128GB Unified Memory or 24GB Ultra GDDR6X graphics memory",
bandWidth: "400 GB/s to 1,008 GB/s ultra-level graphics speed",
modelGoal: "Command R+ 104B (Q3) or Llama-3-70B-Instruct and local database in parallel",
verdict: "DEEP THINKER MATRIX: Indexes huge business catalogs, website records, and contracts (thousands of pages) in minutes. Query archives completely offline.",
setupTools: "AnythingLLM visual workspace server running completely locally on your system desk",
purchaseTip: "Tip: Speed is determined by memory bandwidth. Focus entirely on graphics bandwidth (over 500GB/s is the sweet spot!)."
};
} else {
return {
machineType: "Pro Workstation with 2x Nvidia RTX 4090 or Mac Studio M3 Ultra (192GB RAM)",
ramType: "48GB Graphics Memory (Dual Cards) or 192GB Unified Memory",
bandWidth: "Over 800 GB/s massive pipeline speed",
modelGoal: "Mixtral 8x22B (Q4) or customized local 70B workflow automation pipelines",
verdict: "CREATIVE AGENCY POWER: Ultimate speed for simultaneous content generation and data tasks. Automatically drafts, translates, and formats blog posts in parallel.",
setupTools: "AnythingLLM visual agency tools or local docker visual desktop apps",
purchaseTip: "Tip: Make sure you use a top-shelf power supply if custom-building dual graphics cards to handle high content workloads gracefully."
};
}
} else {
return {
machineType: "Dedicated Private In-House Server Nodes (Gigabyte Server with 4x Nvidia RTX cards)",
ramType: "96GB to 384GB high-grade Server Memory + massive graphics pools",
bandWidth: "1.5 TB/s to 3.2 TB/s ultra-bandwidth networks",
modelGoal: "Llama-3.1-405B (Q4 quantization) or multiple parallel Mixtral instances",
verdict: "COMPLETE OFFICE CLOUD REPLACEMENT: Serves private email, content, and search tools across your entire company. Replaces team subscriptions completely.",
setupTools: "LM Studio Commercial Server or AnythingLLM Enterprise Workspace (Simple admin dashboard)",
purchaseTip: "Tip: Place these in a cooled server room or closet. Enterprise server configurations require proper cooling and ventilation."
};
}
};
+26
View File
@@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "ES2022",
"experimentalDecorators": true,
"useDefineForClassFields": false,
"module": "ESNext",
"lib": [
"ES2022",
"DOM",
"DOM.Iterable"
],
"skipLibCheck": true,
"moduleResolution": "bundler",
"isolatedModules": true,
"moduleDetection": "force",
"allowJs": true,
"jsx": "react-jsx",
"paths": {
"@/*": [
"./*"
]
},
"allowImportingTsExtensions": true,
"noEmit": true
}
}
+15
View File
@@ -0,0 +1,15 @@
import tailwindcss from '@tailwindcss/vite';
import react from '@vitejs/plugin-react';
import path from 'path';
import {defineConfig} from 'vite';
export default defineConfig(() => {
return {
plugins: [react(), tailwindcss()],
resolve: {
alias: {
'@': path.resolve(__dirname, '.'),
},
}
};
});