320 lines
16 KiB
TypeScript
320 lines
16 KiB
TypeScript
import React, { useState } from 'react';
|
|
import {
|
|
Palette,
|
|
Copy,
|
|
Check,
|
|
Sun,
|
|
Smile,
|
|
CheckCircle2,
|
|
Brush
|
|
} from 'lucide-react';
|
|
import { COLOR_PALETTE, ART_DIRECTION_GUIDE, CHARACTERS } from '../data/storyData';
|
|
import { soundManager } from '../utils/audio';
|
|
|
|
interface ArtDirectionViewProps {
|
|
isBedtimeMode: boolean;
|
|
}
|
|
|
|
export const ArtDirectionView: React.FC<ArtDirectionViewProps> = ({ isBedtimeMode }) => {
|
|
const [copiedHex, setCopiedHex] = useState<string | null>(null);
|
|
const [customStyle, setCustomStyle] = useState<string>('digital-gouache');
|
|
const [customSubject, setCustomSubject] = useState<string>('Pip holding his willow brush looking at Caelum');
|
|
const [customMood, setCustomMood] = useState<string>('Warm golden twilight');
|
|
|
|
const handleCopyHex = (hex: string) => {
|
|
soundManager.playPop();
|
|
navigator.clipboard.writeText(hex);
|
|
setCopiedHex(hex);
|
|
setTimeout(() => setCopiedHex(null), 2000);
|
|
};
|
|
|
|
const generatedCustomPrompt = `Whimsical children's picture book illustration of ${customSubject}. ${customMood}, in ${customStyle === 'digital-gouache' ? 'soft digital gouache and textured watercolor' : customStyle === 'classic-pastel' ? 'classic soft oil pastel with hand-drawn colored pencil contours' : 'dreamy storybook gouache with visible paper tooth grain'}. Color palette featuring ${COLOR_PALETTE.map(c => c.name).slice(0, 3).join(', ')}. Friendly character expressions, gentle magical atmosphere, heartwarming children's literature style.`;
|
|
|
|
return (
|
|
<div className={`min-h-[calc(100vh-7rem)] py-8 px-4 sm:px-6 lg:px-8 transition-colors duration-300 ${
|
|
isBedtimeMode
|
|
? 'bg-gradient-to-b from-indigo-950 via-slate-900 to-indigo-950 text-indigo-100'
|
|
: 'bg-[#faf6ee] text-stone-900'
|
|
}`}>
|
|
<div className="max-w-7xl mx-auto space-y-8">
|
|
{/* Header */}
|
|
<div className={`p-6 sm:p-8 rounded-3xl border shadow-sm ${
|
|
isBedtimeMode
|
|
? 'bg-slate-900/90 border-indigo-800'
|
|
: 'bg-white border-amber-200/90'
|
|
}`}>
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<span className="px-3 py-1 rounded-full text-xs font-bold uppercase tracking-wider bg-rose-500/10 text-rose-700 dark:text-rose-400 border border-rose-300/40">
|
|
Art & Visual Direction Bible
|
|
</span>
|
|
<span className="text-xs text-stone-500 dark:text-indigo-300">
|
|
{ART_DIRECTION_GUIDE.styleName}
|
|
</span>
|
|
</div>
|
|
<h2 className="text-2xl sm:text-3xl font-heading font-bold text-amber-950 dark:text-white">
|
|
Color Palette, Expressions & Artistic Philosophy
|
|
</h2>
|
|
<p className="mt-1 text-sm sm:text-base text-stone-600 dark:text-indigo-200 max-w-3xl leading-relaxed">
|
|
Detailed art notes crafted so that any illustrator or AI visual model can render consistent, heartwarming, award-winning storybook spreads.
|
|
</p>
|
|
</div>
|
|
|
|
{/* Master Color Palette Section */}
|
|
<div className={`p-6 sm:p-8 rounded-3xl border ${
|
|
isBedtimeMode ? 'bg-slate-900 border-indigo-800' : 'bg-white border-amber-200/90'
|
|
}`}>
|
|
<div className="flex items-center justify-between mb-6">
|
|
<div className="flex items-center gap-2">
|
|
<Palette className="w-5 h-5 text-amber-600 dark:text-amber-400" />
|
|
<h3 className="text-xl font-heading font-bold text-stone-900 dark:text-white">
|
|
Master Storybook Color Palette
|
|
</h3>
|
|
</div>
|
|
<span className="text-xs font-semibold text-stone-500 dark:text-indigo-300">
|
|
Click any swatch to copy Hex
|
|
</span>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
{COLOR_PALETTE.map((swatch) => (
|
|
<div
|
|
key={swatch.hex}
|
|
onClick={() => handleCopyHex(swatch.hex)}
|
|
className="p-4 rounded-2xl border border-stone-200 dark:border-indigo-800 bg-stone-50 dark:bg-indigo-950/40 hover:shadow-md cursor-pointer transition-all group"
|
|
>
|
|
<div className="flex items-center gap-3 mb-3">
|
|
<div
|
|
style={{ backgroundColor: swatch.hex }}
|
|
className="w-12 h-12 rounded-2xl shadow-inner border-2 border-white dark:border-slate-800 shrink-0 group-hover:scale-105 transition-transform"
|
|
/>
|
|
<div>
|
|
<h4 className="font-heading font-bold text-sm text-stone-900 dark:text-white">
|
|
{swatch.name}
|
|
</h4>
|
|
<div className="flex items-center gap-1.5 text-xs font-mono font-bold text-amber-700 dark:text-amber-400">
|
|
<span>{swatch.hex}</span>
|
|
{copiedHex === swatch.hex ? (
|
|
<Check className="w-3.5 h-3.5 text-emerald-600" />
|
|
) : (
|
|
<Copy className="w-3.5 h-3.5 opacity-40 group-hover:opacity-100" />
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-1 text-xs">
|
|
<p className="text-stone-700 dark:text-stone-300">
|
|
<strong className="text-stone-900 dark:text-white">Usage:</strong> {swatch.usage}
|
|
</p>
|
|
<p className="text-stone-500 dark:text-indigo-300 italic">
|
|
<strong className="text-stone-700 dark:text-stone-200 not-italic">Mood:</strong> {swatch.mood}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Character Expression & Anatomy Guidelines */}
|
|
<div className={`p-6 sm:p-8 rounded-3xl border ${
|
|
isBedtimeMode ? 'bg-slate-900 border-indigo-800' : 'bg-white border-amber-200/90'
|
|
}`}>
|
|
<div className="flex items-center gap-2 mb-6">
|
|
<Smile className="w-5 h-5 text-amber-600 dark:text-amber-400" />
|
|
<h3 className="text-xl font-heading font-bold text-stone-900 dark:text-white">
|
|
Character Expression & Visual Identity Rules
|
|
</h3>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
{CHARACTERS.map((char) => (
|
|
<div
|
|
key={char.name}
|
|
className="p-5 rounded-2xl border border-stone-200 dark:border-indigo-800 bg-stone-50/70 dark:bg-indigo-950/40 space-y-3"
|
|
>
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center gap-3">
|
|
<span className="text-3xl">{char.avatarEmoji}</span>
|
|
<div>
|
|
<h4 className="font-heading font-bold text-base text-stone-900 dark:text-white">
|
|
{char.name}
|
|
</h4>
|
|
<span className="text-xs font-semibold text-stone-500 dark:text-indigo-300">
|
|
{char.role}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<span
|
|
style={{ backgroundColor: `${char.accentColor}20`, color: char.accentColor, borderColor: `${char.accentColor}40` }}
|
|
className="text-xs font-bold px-2.5 py-1 rounded-full border"
|
|
>
|
|
{char.species}
|
|
</span>
|
|
</div>
|
|
|
|
<div className="space-y-2 text-xs sm:text-sm text-stone-700 dark:text-stone-300">
|
|
<p>
|
|
<strong className="text-stone-900 dark:text-white">Key Visual Markers:</strong> {char.appearance}
|
|
</p>
|
|
<p>
|
|
<strong className="text-stone-900 dark:text-white">Signature Gesture / Quirk:</strong> {char.quirk}
|
|
</p>
|
|
<p>
|
|
<strong className="text-stone-900 dark:text-white">Emotional Color Transition:</strong> {char.name === 'Pip' ? 'Quills ripple like grass when inspired; scarf flaps cheerfully.' : char.name === 'Caelum' ? 'Shifts from misty slate-gray (timid) to soft lavender (shy) to radiant sunset gold and rosé (confident).' : char.name === 'Barnaby' ? 'Eyes crinkle warmly into crescents; spectacles catch amber rim-light.' : 'Wings flutter in excited loops; chest puffs with sky-blue pride.'}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
{/* Golden Rules Box */}
|
|
<div className="mt-6 p-4 rounded-2xl bg-amber-50 dark:bg-indigo-950/60 border border-amber-200 dark:border-indigo-800">
|
|
<h5 className="font-heading font-bold text-xs uppercase tracking-wider text-amber-800 dark:text-amber-300 mb-2">
|
|
Core Principles for the Children's Illustrator
|
|
</h5>
|
|
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3 text-xs text-stone-700 dark:text-stone-300">
|
|
<div className="flex items-start gap-2">
|
|
<CheckCircle2 className="w-4 h-4 text-emerald-600 shrink-0 mt-0.5" />
|
|
<span><strong>No Harsh Black Outlines:</strong> Use deep sepia, indigo, or forest bark for line work.</span>
|
|
</div>
|
|
<div className="flex items-start gap-2">
|
|
<CheckCircle2 className="w-4 h-4 text-emerald-600 shrink-0 mt-0.5" />
|
|
<span><strong>Tactile Paper Texture:</strong> Retain visible rag-paper tooth and watercolor bloom edges.</span>
|
|
</div>
|
|
<div className="flex items-start gap-2">
|
|
<CheckCircle2 className="w-4 h-4 text-emerald-600 shrink-0 mt-0.5" />
|
|
<span><strong>Gentle Scale & Proximity:</strong> Caelum hovers close to the grass to invite cuddles.</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Lighting Keys Across The Story */}
|
|
<div className={`p-6 sm:p-8 rounded-3xl border ${
|
|
isBedtimeMode ? 'bg-slate-900 border-indigo-800' : 'bg-white border-amber-200/90'
|
|
}`}>
|
|
<div className="flex items-center gap-2 mb-6">
|
|
<Sun className="w-5 h-5 text-amber-600 dark:text-amber-400" />
|
|
<h3 className="text-xl font-heading font-bold text-stone-900 dark:text-white">
|
|
Lighting & Atmospheric Keys Across Acts
|
|
</h3>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
{ART_DIRECTION_GUIDE.lightingKeys.map((key, idx) => (
|
|
<div
|
|
key={idx}
|
|
className="p-5 rounded-2xl border border-stone-200 dark:border-indigo-800 bg-stone-50 dark:bg-indigo-950/40 space-y-3"
|
|
>
|
|
<div className="flex items-center justify-between">
|
|
<span className="text-xs font-bold uppercase tracking-wider px-2.5 py-0.5 rounded-full bg-amber-100 dark:bg-indigo-900 text-amber-800 dark:text-amber-300 border border-amber-200 dark:border-indigo-700">
|
|
{key.scene}
|
|
</span>
|
|
<span className="text-[11px] font-mono text-stone-500 dark:text-indigo-300">
|
|
{key.colorTemp}
|
|
</span>
|
|
</div>
|
|
<h4 className="font-heading font-bold text-base text-stone-900 dark:text-white">
|
|
{key.mood}
|
|
</h4>
|
|
<p className="text-xs sm:text-sm text-stone-600 dark:text-indigo-200 font-reading leading-relaxed">
|
|
{key.description}
|
|
</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Interactive Storybook Prompt Builder */}
|
|
<div className={`p-6 sm:p-8 rounded-3xl border ${
|
|
isBedtimeMode ? 'bg-slate-900 border-indigo-800' : 'bg-white border-amber-200/90'
|
|
}`}>
|
|
<div className="flex items-center gap-2 mb-4">
|
|
<Brush className="w-5 h-5 text-rose-500" />
|
|
<div>
|
|
<h3 className="text-xl font-heading font-bold text-stone-900 dark:text-white">
|
|
Interactive Illustration Prompt Builder
|
|
</h3>
|
|
<p className="text-xs text-stone-500 dark:text-indigo-300">
|
|
Generate new children's book scene prompts matching this art bible
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
|
|
<div>
|
|
<label className="block text-xs font-bold uppercase text-stone-600 dark:text-indigo-300 mb-1">
|
|
Subject & Action
|
|
</label>
|
|
<input
|
|
type="text"
|
|
value={customSubject}
|
|
onChange={(e) => setCustomSubject(e.target.value)}
|
|
className="w-full px-3 py-2 text-sm rounded-xl border border-stone-300 dark:border-indigo-700 bg-stone-50 dark:bg-indigo-950 text-stone-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-amber-500"
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<label className="block text-xs font-bold uppercase text-stone-600 dark:text-indigo-300 mb-1">
|
|
Lighting & Time of Day
|
|
</label>
|
|
<select
|
|
value={customMood}
|
|
onChange={(e) => setCustomMood(e.target.value)}
|
|
className="w-full px-3 py-2 text-sm rounded-xl border border-stone-300 dark:border-indigo-700 bg-stone-50 dark:bg-indigo-950 text-stone-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-amber-500"
|
|
>
|
|
<option value="Morning sunbeams streaming through dewy oak leaves">Morning Dewy Sunbeams</option>
|
|
<option value="Warm golden twilight with pastel rainbow mist">Warm Golden Twilight</option>
|
|
<option value="Velvet indigo bedtime sky with twinkling stars and lanterns">Velvet Bedtime Stars</option>
|
|
<option value="Misty lavender afternoon breeze over purple clover">Misty Lavender Afternoon</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<label className="block text-xs font-bold uppercase text-stone-600 dark:text-indigo-300 mb-1">
|
|
Illustration Medium
|
|
</label>
|
|
<select
|
|
value={customStyle}
|
|
onChange={(e) => setCustomStyle(e.target.value)}
|
|
className="w-full px-3 py-2 text-sm rounded-xl border border-stone-300 dark:border-indigo-700 bg-stone-50 dark:bg-indigo-950 text-stone-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-amber-500"
|
|
>
|
|
<option value="digital-gouache">Digital Gouache & Soft Watercolor</option>
|
|
<option value="classic-pastel">Classic Soft Pastel & Colored Pencil</option>
|
|
<option value="storybook-ragpaper">Storybook Gouache with Rag-paper Grain</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="p-4 rounded-2xl bg-amber-50 dark:bg-indigo-950/70 border border-amber-200 dark:border-indigo-800 space-y-2">
|
|
<div className="flex items-center justify-between">
|
|
<span className="text-xs font-heading font-bold uppercase text-amber-800 dark:text-amber-300">
|
|
Generated Artist / AI Prompt:
|
|
</span>
|
|
<button
|
|
onClick={() => handleCopyHex(generatedCustomPrompt)}
|
|
className="flex items-center gap-1 text-xs font-bold text-amber-700 dark:text-amber-300 hover:text-amber-900 bg-white dark:bg-indigo-900 px-2.5 py-1 rounded-lg border border-amber-200 dark:border-indigo-700"
|
|
>
|
|
{copiedHex === generatedCustomPrompt ? (
|
|
<>
|
|
<Check className="w-3.5 h-3.5 text-emerald-600" />
|
|
<span>Copied!</span>
|
|
</>
|
|
) : (
|
|
<>
|
|
<Copy className="w-3.5 h-3.5" />
|
|
<span>Copy Generated Prompt</span>
|
|
</>
|
|
)}
|
|
</button>
|
|
</div>
|
|
<p className="text-xs sm:text-sm font-reading italic text-stone-800 dark:text-stone-200 leading-relaxed">
|
|
"{generatedCustomPrompt}"
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|