import React, { useEffect, useMemo, useState } from "react"; import { motion } from "framer-motion"; import { Heart, ShieldCheck, Sparkles, Video, Mic, Image as ImageIcon, Lock, Crown, Check, Wand2, Star, MessageCircle, SlidersHorizontal, CreditCard, UserCheck, BadgeCheck, Brain, Flame, } from "lucide-react"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Slider } from "@/components/ui/slider"; import { Switch } from "@/components/ui/switch"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Badge } from "@/components/ui/badge"; import { Progress } from "@/components/ui/progress"; const baseAvatars = [ { id: "luna", name: "Luna", archetype: "Warm romantic", palette: ["from-fuchsia-500", "via-rose-400", "to-amber-300"], face: "oval", vibe: "Playful", }, { id: "kai", name: "Kai", archetype: "Confident charmer", palette: ["from-cyan-500", "via-sky-400", "to-indigo-300"], face: "square", vibe: "Calm", }, { id: "nova", name: "Nova", archetype: "Androgynous dreamer", palette: ["from-violet-500", "via-purple-400", "to-pink-300"], face: "heart", vibe: "Curious", }, ]; const moods = ["Tender", "Flirty", "Adventurous", "Protective", "Witty", "Private 18+"]; const voices = ["Velvet", "Low Glow", "Bright Silk", "Noir Whisper"]; const styles = ["Editorial", "Soft cinematic", "Night luxe", "Minimal modern"]; const plans = { free: { label: "Free", avatars: 1, multimodal: false, adult: false }, plus: { label: "Plus", avatars: 3, multimodal: true, adult: false }, black: { label: "Black Label", avatars: 12, multimodal: true, adult: true }, }; function cn(...parts: (string | false | undefined)[]) { return parts.filter(Boolean).join(" "); } function Portrait({ palette, face, intensity = 55 }: { palette: string[]; face: string; intensity?: number }) { const faceClass = face === "square" ? "rounded-[28%]" : face === "heart" ? "rounded-[38%]" : "rounded-[44%]"; return (
); } function generateReply(prompt: string, state: any) { const tone = state.mood === "Private 18+" ? "velvet" : state.mood.toLowerCase(); const openers = { Tender: "I’m here with you.", Flirty: "You have my full attention.", Adventurous: "Let’s make this feel cinematic.", Protective: "You can relax here.", Witty: "Good. We’re finally getting interesting.", "Private 18+": "Private mode is on and your preferences are locked in.", } as Record; const line = openers[state.mood] || "I’m tuned in."; const cue = prompt ? ` You said: “${prompt}”` : ""; const persona = `${state.name} is using a ${tone} tone with ${state.voice} voice styling.`; const memory = ` Memory anchor: ${state.memory}% continuity, ${state.style} visual treatment.`; if (state.mode === "image") { return `${line}${cue} I’d render a ${state.style.toLowerCase()} portrait with ${state.glow}% glamour, ${state.voice.toLowerCase()} energy, and ${state.boundaries ? "tasteful" : "unguarded"} framing.${memory}`; } if (state.mode === "voice") { return `${line}${cue} Voice scene ready: breath pacing softened, cadence set to ${state.voice}, response shaped for a ${state.mood.toLowerCase()} interaction.${memory}`; } return `${line}${cue} ${persona}${memory}`; } export default function MyAiLoveBetterDemo() { const [plan, setPlan] = useState("plus"); const [verified, setVerified] = useState(false); const [loggedIn, setLoggedIn] = useState(false); const [showAgeGate, setShowAgeGate] = useState(false); const [selected, setSelected] = useState(baseAvatars[0]); const [name, setName] = useState(baseAvatars[0].name); const [mood, setMood] = useState("Tender"); const [voice, setVoice] = useState(voices[0]); const [style, setStyle] = useState(styles[0]); const [glow, setGlow] = useState(62); const [memory, setMemory] = useState(78); const [multiAvatar, setMultiAvatar] = useState(true); const [boundaries, setBoundaries] = useState(true); const [mode, setMode] = useState<"chat" | "voice" | "image">("chat"); const [prompt, setPrompt] = useState("Plan a late-night rooftop date and remember I like jasmine tea."); const [messages, setMessages] = useState([ { role: "system", text: "Welcome back. Your companion profile and preferences are restored locally for this demo." }, { role: "assistant", text: "I saved your jasmine tea preference, your low-light portrait style, and your preference for slow, thoughtful pacing." }, ]); useEffect(() => { const saved = localStorage.getItem("myailove-better-demo"); if (saved) { try { const parsed = JSON.parse(saved); setPlan(parsed.plan || "plus"); setVerified(!!parsed.verified); setLoggedIn(!!parsed.loggedIn); setSelected(parsed.selected || baseAvatars[0]); setName(parsed.name || baseAvatars[0].name); setMood(parsed.mood || "Tender"); setVoice(parsed.voice || voices[0]); setStyle(parsed.style || styles[0]); setGlow(parsed.glow ?? 62); setMemory(parsed.memory ?? 78); setMultiAvatar(parsed.multiAvatar ?? true); setBoundaries(parsed.boundaries ?? true); setMessages(parsed.messages || messages); } catch {} } }, []); useEffect(() => { localStorage.setItem( "myailove-better-demo", JSON.stringify({ plan, verified, loggedIn, selected, name, mood, voice, style, glow, memory, multiAvatar, boundaries, messages, }) ); }, [plan, verified, loggedIn, selected, name, mood, voice, style, glow, memory, multiAvatar, boundaries, messages]); const planConfig = plans[plan]; const canUseAdult = planConfig.adult && verified; const output = useMemo( () => generateReply(prompt, { mood, voice, style, glow, memory, name, mode, boundaries }), [prompt, mood, voice, style, glow, memory, name, mode, boundaries] ); function send() { const requestedAdult = /adult|private|after dark|uncensored|nsfw/i.test(prompt) || mood === "Private 18+"; if (requestedAdult && !canUseAdult) { setShowAgeGate(true); setMessages((m) => [ ...m, { role: "user", text: prompt }, { role: "assistant", text: "Private 18+ mode requires a Black Label plan and completed age verification. Everything else is available now." }, ]); return; } setMessages((m) => [...m, { role: "user", text: prompt }, { role: "assistant", text: output }]); } function chooseAvatar(avatar: any) { if (!planConfig.avatars || (avatar.id !== selected.id && planConfig.avatars < 2 && multiAvatar)) return; setSelected(avatar); setName(avatar.name); } function upgrade(nextPlan: keyof typeof plans) { setPlan(nextPlan); setLoggedIn(true); } return (
myailove.ai
Tasteful companion product demo
18,472 online
Out-positioned for trust, retention, and conversion

A better AI companion demo: premium, coherent, and built to convert.

Instead of random stock photos and shallow promises, this prototype leans into what actually wins in the category: memory, customization, voice, tasteful visual identity, clear monetization, and gated private mode.

{[ "Memory-first relationship loop", "Tasteful premium funnel", "Multi-avatar upsell", "Private 18+ gating", "Local persistence for demo realism", ].map((x) => ( {x} ))}
{[ { label: "What Replika proves", value: "care" }, { label: "What Nomi proves", value: "memory" }, { label: "What Candy proves", value: "multimodal" }, ].map((item) => (
{item.label}
{item.value}
))}
{style}
{name}
{selected.archetype} • {mood} • {voice}
Memory continuity
{memory}%
Build your companion Consistent art direction beats random photo IDs every time.
{baseAvatars.map((avatar, index) => { const locked = index >= planConfig.avatars; return ( ); })}
setName(e.target.value)} className="border-white/10 bg-black/25 text-white" />
{voices.map((v) => ( ))}
{styles.map((s) => ( ))}
Glamour level{glow}%
setGlow(v[0])} />
Memory continuity{memory}%
setMemory(v[0])} />
{moods.map((item) => ( ))}
Functional session demo Stateful front-end flow: plans, gating, content mode, prompts, and local persistence. Studio Session Monetization
{[ { key: "chat", label: "Text scene", icon: MessageCircle }, { key: "voice", label: "Voice scene", icon: Mic }, { key: "image", label: "Portrait scene", icon: ImageIcon }, ].map((item) => { const Icon = item.icon; return ( ); })}
setPrompt(e.target.value)} className="border-white/10 bg-black/25 text-white" />
Generated output preview
{output}
{name}
{loggedIn ? "Memory restored" : "Guest session"}
{planConfig.label}
{messages.map((m, i) => (
{m.text}
))}
upgrade("free")} /> upgrade("plus")} /> upgrade("black")} />
Age verification
Private 18+ mode stays locked until plan + verification are both complete.
{verified ? "Verified 18+" : "Not verified"}
{[ { icon: Brain, title: "Retention loop", text: "Memory anchors, saved preferences, and multi-avatar collections raise session return rates." }, { icon: SlidersHorizontal, title: "Tasteful customization", text: "Users shape tone, style, voice, and pace without the product looking cheap or random." }, { icon: CreditCard, title: "Clear monetization", text: "Free proves value. Plus unlocks multimodal features. Black Label unlocks private mode and more slots." }, { icon: BadgeCheck, title: "Trust posture", text: "Private mode is gated, visually separated, and never confused with the core product experience." }, ].map((item) => { const Icon = item.icon; return (
{item.title}
{item.text}
); })}
{showAgeGate && (
Private 18+ access Tasteful gating for premium private interactions. This demo simulates the product flow without rendering explicit content.
Requirements: Black Label subscription, authenticated account, and completed age verification.
)}
); } function Metric({ icon: Icon, label, value }: any) { return (
{label}
{value}
); } function PlanCard({ name, price, features, active, cta, onClick, highlight = false }: any) { return (
{name}
{highlight ? Best starter : null}
{price} / mo
{features.map((f: string) => (
{f}
))}
); } function ToggleRow({ label, helper, checked, onCheckedChange }: any) { return (
{label}
{helper}
); } function StatusPill({ ok, label }: any) { return
{label}
; }