Prompt Details
Model
(gemini-3.1-pro)
Token size
3,884
Example input
[Coloring Book Character App for printable creators]: Coloring Book Character App for printable creators
[KDP sellers, Etsy sellers, kids aged 5 to 10]: KDP sellers, Etsy sellers, kids aged 5 to 10
[Cute full-body characters for coloring pages]: Cute full-body characters for coloring pages
[Clean black white preview, simple kid-friendly UI, soft transitions]: Clean black white preview, simple kid-friendly UI, soft transitions
[Coloring page prompts, cover prompt, variation generator, TXT export]: Coloring page prompts, cover prompt, variation generator, TXT export
Example output
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ColoryMascot Studio - Printable IP Generator</title>
<style>
/* CSS Framework & Design System */
:root {
--bg: #f8fafc;
--surface: #ffffff;
--primary: #0f172a;
--primary-hover: #334155;
--border: #e2e8f0;
--border-focus: #94a3b8;
--text: #0f172a;
--text-muted: #64748b;
--accent: #3b82f6;
--success: #10b981;
--warning: #f59e0b;
--danger: #ef4444;
--radius-md: 0.75rem;
--radius-lg: 1.5rem;
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, -apple-system, sans-serif; background-color: var(--bg); color: var(--text); line-height: 1.5; padding-bottom: 4rem; }
/* Typography */
h1, h2, h3, h4 { font-weight: 800; letter-spacing: -0.025em; line-height: 1.2; }
h1 { font-size: 2.25rem; }
h2 { font-size: 1.5rem; margin-bottom: 1rem; }
h3 { font-size: 1.25rem; margin-bottom: 0.5rem; }
p { margin-bottom: 1rem; color: var(--text-muted); }
strong { color: var(--text); }
/* Layout */
.container { max-width: 1400px; margin: 0 auto; padding: 0 1.5rem; }
.grid { display: grid; gap: 1.5rem; }
.grid-cols-12 { grid-template-columns: repeat(12, 1fr); }
.col-span-4 { grid-column: span 4; }
.col-span-8 { grid-column: span 8; }
.flex { display: flex; }
.flex-col { flex-direction: column; }
.items-center { align-items: center; }
.justify-between { justify-content: space-between; }
.justify-center { justify-content: center; }
.gap-2 { gap: 0.5rem; } .gap-4 { gap: 1rem; } .gap-6 { gap: 1.5rem; }
.mt-4 { margin-top: 1rem; } .mt-8 { margin-top: 2rem; } .mb-4 { margin-bottom: 1rem; } .mb-8 { margin-bottom: 2rem; }
.p-4 { padding: 1rem; } .p-6 { padding: 1.5rem; }
/* Components */
.card { background: var(--surface); border: 2px solid var(--border); border-radius: var(--radius-lg); padding: 1.5rem; box-shadow: var(--shadow-sm); }
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem; padding: 0.75rem 1.25rem; border-radius: 999px; font-weight: 600; font-size: 0.875rem; cursor: pointer; transition: all 0.2s ease; border: 2px solid transparent; text-decoration: none; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
.btn-primary { background: var(--primary); color: white; }
.btn-primary:hover:not(:disabled) { background: var(--primary-hover); transform: translateY(-1px); box-shadow: var(--shadow-md); }
.btn-secondary { background: white; border-color: var(--border); color: var(--text); }
.btn-secondary:hover:not(:disabled) { border-color: var(--primary); color: var(--primary); }
.btn-outline { background: transparent; border-color: var(--primary); color: var(--primary); }
.btn-outline:hover:not(:disabled) { background: var(--primary); color: white; }
.btn-small { padding: 0.5rem 1rem; font-size: 0.75rem; }
.btn-danger { background: var(--danger); color: white; }
.input-group { display: flex; flex-direction: column; gap: 0.375rem; margin-bottom: 1rem; }
.label { font-size: 0.875rem; font-weight: 600; color: var(--text); }
.input, .select { padding: 0.625rem 1rem; border: 2px solid var(--border); border-radius: var(--radius-md); font-size: 0.875rem; background: var(--bg); transition: all 0.2s; color: var(--text); width: 100%; font-family: inherit; }
.input:focus, .select:focus { outline: none; border-color: var(--primary); background: white; box-shadow: 0 0 0 3px rgba(15, 23, 42, 0.1); }
.chip { display: inline-flex; align-items: center; padding: 0.25rem 0.75rem; background: var(--bg); border: 1px solid var(--border); border-radius: 999px; font-size: 0.75rem; font-weight: 600; color: var(--text-muted); }
.chip.success { background: #dcfce7; color: #166534; border-color: #bbf7d0; }
.chip.warning { background: #fef3c7; color: #92400e; border-color: #fde68a; }
/* UI Elements */
.tabs { display: flex; gap: 0.5rem; overflow-x: auto; padding-bottom: 0.5rem; border-bottom: 2px solid var(--border); margin-bottom: 1.5rem; scrollbar-width: none; }
.tabs::-webkit-scrollbar { display: none; }
.tab { padding: 0.5rem 1rem; font-weight: 600; color: var(--text-muted); cursor: pointer; border: none; background: none; border-bottom: 2px solid transparent; margin-bottom: -2px; white-space: nowrap; transition: all 0.2s; }
.tab:hover { color: var(--text); }
.tab.active { color: var(--primary); border-bottom-color: var(--primary); }
.tab-content { display: none; animation: fadeIn 0.4s cubic-bezier(0.16, 1, 0.3, 1); }
.tab-content.active { display: block; }
/* Generated Output Styles */
.output-block { background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-md); padding: 1.5rem; margin-bottom: 1.5rem; }
.output-block h4 { border-bottom: 2px solid var(--border); padding-bottom: 0.5rem; margin-bottom: 1rem; color: var(--primary); }
.output-text { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 0.875rem; white-space: pre-wrap; color: var(--primary); background: white; padding: 1rem; border-radius: var(--radius-md); border: 1px solid var(--border); }
/* Mascot CSS Art */
.mascot-preview { width: 140px; height: 140px; background: white; border: 8px solid var(--primary); border-radius: 40% 60% 60% 40% / 50% 50% 50% 50%; position: relative; animation: float 4s ease-in-out infinite; margin: 0 auto; box-shadow: inset -12px -12px 0px rgba(0,0,0,0.04), 0 10px 20px rgba(0,0,0,0.1); }
.mascot-eyes { position: absolute; top: 45px; left: 0; width: 100%; display: flex; justify-content: center; gap: 30px; }
.mascot-eye { width: 16px; height: 16px; background: var(--primary); border-radius: 50%; animation: blink 4s infinite; }
.mascot-smile { position: absolute; top: 70px; left: 50%; transform: translateX(-50%); width: 24px; height: 12px; border-bottom: 6px solid var(--primary); border-radius: 0 0 20px 20px; }
.mascot-blush { position: absolute; top: 60px; left: 0; width: 100%; display: flex; justify-content: center; gap: 50px; opacity: 0.2; }
.blush-spot { width: 16px; height: 10px; background: var(--primary); border-radius: 50%; }
/* Utils & Animations */
@keyframes float { 0%, 100% { transform: translateY(0) rotate(0deg); } 50% { transform: translateY(-10px) rotate(2deg); } }
@keyframes blink { 0%, 96%, 98% { transform: scaleY(1); } 97% { transform: scaleY(0.1); } }
@keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
.hidden { display: none !important; }
.toast { position: fixed; bottom: 2rem; right: 2rem; background: var(--primary); color: white; padding: 1rem 1.5rem; border-radius: var(--radius-md); box-shadow: var(--shadow-md); z-index: 1000; animation: slideUp 0.3s ease; }
@keyframes slideUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
.score-circle { width: 80px; height: 80px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 1.5rem; font-weight: 800; border: 6px solid var(--border); color: var(--primary); transition: all 0.5s; background: white;}
#loading-overlay { position: fixed; inset: 0; background: rgba(255,255,255,0.8); backdrop-filter: blur(4px); z-index: 50; display: flex; flex-direction: column; align-items: center; justify-content: center; }
.spinner { width: 40px; height: 40px; border: 4px solid var(--border); border-top-color: var(--primary); border-radius: 50%; animation: spin 1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
/* Print Styles */
@media print {
body { background: white; color: black; padding: 0; }
.no-print, .input-panel, header, .tabs { display: none !important; }
.col-span-8 { grid-column: span 12 !important; }
.card { border: none; box-shadow: none; padding: 0; }
.output-block { page-break-inside: avoid; border: 1px solid #ccc; }
}
/* Mobile Responsive */
@media (max-width: 1024px) {
.col-span-4, .col-span-8 { grid-column: span 12; }
.container { padding: 0 1rem; }
.mascot-preview { width: 100px; height: 100px; }
.mascot-eyes { top: 30px; gap: 20px; }
.mascot-smile { top: 50px; }
.mascot-blush { top: 40px; gap: 36px; }
}
/* Custom Scrollbar for textareas */
textarea { resize: vertical; min-height: 80px; }
</style>
</head>
<body>
<header class="container mt-8 mb-8 no-print">
<div class="card bg-primary text-white" style="background: var(--primary); color: white;">
<div class="flex items-center justify-between flex-col md:flex-row gap-6" style="flex-wrap: wrap;">
<div style="flex: 1;">
<div class="flex gap-2 mb-2">
<span class="chip">No External APIs</span>
<span class="chip">Local Save</span>
<span class="chip">Print Ready</span>
</div>
<h1 style="color: white; margin-bottom: 0.5rem;">ColoryMascot Studio</h1>
<p style="color: #cbd5e1; font-size: 1.125rem; max-width: 600px;">Generate complete, IP-safe, kid-friendly mascot systems and coloring page prompts for KDP, Etsy, and creative printables.</p>
<div class="flex gap-4 mt-6">
<button class="btn btn-secondary" style="border-color: white;" id="btn-demo-data">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline></svg>
Load Demo Data
</button>
<button class="btn" style="background: white; color: var(--primary);" id="btn-scroll-gen">Start Generating</button>
</div>
</div>
<div class="p-6">
<div class="mascot-preview">
<div class="mascot-eyes">
<div class="mascot-eye"></div>
<div class="mascot-eye"></div>
</div>
<div class="mascot-blush">
<div class="blush-spot"></div>
<div class="blush-spot"></div>
</div>
<div class="mascot-smile"></div>
</div>
</div>
</div>
</div>
</header>
<main class="container grid grid-cols-12">
<!-- LEFT: INPUT STUDIO -->
<aside class="col-span-4 input-panel">
<div class="card mb-4">
<div class="flex justify-between items-center mb-4">
<h2>Input Studio</h2>
<div class="flex gap-2">
<button class="btn btn-small btn-secondary" id="btn-randomize" title="Randomize Ideas">🎲</button>
<button class="btn btn-small btn-secondary" id="btn-clear-form" title="Clear Form">↺</button>
</div>
</div>
<form id="generator-form">
<div class="input-group">
<label class="label">Mascot Base Type *</label>
<input type="text" id="baseType" class="input" placeholder="e.g., Robot, Fox, Mushroom, Star" required>
</div>
<div class="input-group">
<label class="label">Target Audience *</label>
<select id="targetAudience" class="select" required>
<option value="Preschool (Ages 3-5)">Preschool (Ages 3-5)</option>
<option value="Kids (Ages 5-10)" selected>Kids (Ages 5-10)</option>
<option value="Middle School">Middle School</option>
<option value="Parents & Families">Parents & Families</option>
<option value="Teachers & Classrooms">Teachers & Classrooms</option>
<option value="General Commercial Buyers">General Commercial Buyers</option>
</select>
</div>
<div class="input-group">
<label class="label">Commercial Use Case *</label>
<select id="useCase" class="select" required>
<option value="Coloring Book (KDP)">Coloring Book (KDP)</option>
<option value="Sticker Sheet (Etsy)">Sticker Sheet (Etsy)</option>
<option value="Storybook Illustration">Storybook Illustration</option>
<option value="Classroom Printables">Classroom Printables</option>
<option value="Brand Mascot/Logo">Brand Mascot/Logo</option>
<option value="Merchandise (T-Shirts/Mugs)">Merchandise (T-Shirts/Mugs)</option>
</select>
</div>
<div class="input-group">
<label class="label">Theme World</label>
<input type="text" id="themeWorld" class="input" placeholder="e.g., Magic Forest, Space Station, Cozy Town">
</div>
<div class="input-group">
<label class="label">Personality Direction</label>
<input type="text" id="personality" class="input" placeholder="e.g., Brave, Sleepy, Mischievous">
</div>
<div class="input-group">
<label class="label">Visual Style</label>
<select id="visualStyle" class="select">
<option value="Thick Line Art (B&W)">Thick Line Art (B&W) - Best for Coloring</option>
<option value="Kawaii Minimalist">Kawaii Minimalist</option>
<option value="Storybook Sketch">Storybook Sketch</option>
<option value="Flat Vector Mascot">Flat Vector Mascot</option>
<option value="Doodle Style">Doodle Style</option>
</select>
</div>
<div class="input-group">
<label class="label">Signature Prop (Optional)</label>
<input type="text" id="signatureProp" class="input" placeholder="e.g., Star Wand, Oversized Hat, Paintbrush">
</div>
<div class="input-group mb-6">
<label class="label">IP Safety Strictness</label>
<select id="ipSafety" class="select">
<option value="Strict">Strict (Commercial Safe)</option>
<option value="Standard">Standard</option>
</select>
<p style="font-size: 0.75rem; margin-top: 0.25rem;">Removes copyrighted terms automatically.</p>
</div>
<div class="flex flex-col gap-3">
<button type="button" class="btn btn-primary" id="btn-generate-system">Generate Full System</button>
<button type="button" class="btn btn-secondary" id="btn-ip-check">Run IP Safety Check</button>
</div>
</form>
</div>
<!-- Project Manager -->
<div class="card mb-4">
<div class="flex justify-between items-center mb-4">
<h2>Saved Projects</h2>
<span class="chip" id="project-count">0</span>
</div>
<div class="flex gap-2 mb-4">
<button class="btn btn-secondary btn-small" style="flex: 1;" id="btn-save-project">Save Current</button>
<button class="btn btn-outline btn-small" id="btn-clear-projects">Clear</button>
</div>
<div id="project-list" class="flex flex-col gap-2" style="max-height: 200px; overflow-y: auto;">
<p class="text-center" style="font-size: 0.875rem;">No saved projects. Data saves locally to your browser.</p>
</div>
</div>
</aside>
<!-- RIGHT: OUTPUT DASHBOARD -->
<main class="col-span-8">
<div class="card" style="min-height: 800px; display: flex; flex-direction: column;">
<!-- Dashboard Header -->
<div class="flex justify-between items-center mb-6 border-b pb-4 border-gray-200">
<div class="flex items-center gap-4">
<div class="score-circle" id="quality-score" title="Quality Score based on inputs & safety">0</div>
<div>
<h2 style="margin: 0;">Output Canvas</h2>
<p style="margin: 0; font-size: 0.875rem;" id="active-project-name">Unsaved Project</p>
</div>
</div>
<div class="flex gap-2 no-print">
<button class="btn btn-secondary btn-small" id="btn-copy-active">Copy Text</button>
<select class="select" id="exportFormat" style="width: auto; padding: 0.3rem 0.5rem;">
<option value="txt">Export .TXT</option>
<option value="json">Export .JSON</option>
<option value="html">Export .HTML</option>
<option value="pdf">Print / PDF</option>
</select>
<button class="btn btn-primary btn-small" id="btn-export">Download</button>
</div>
</div>
<!-- Empty State -->
<div id="empty-state" class="flex flex-col items-center justify-center flex-1 text-center py-12">
<div class="mascot-preview" style="transform: scale(0.6); animation: none; border-color: var(--border);">
<div class="mascot-eyes" style="top: 55px;"><div class="mascot-eye" style="background: var(--border); animation: none;"></div><div class="mascot-eye" style="background: var(--border); animation: none;"></div></div>
<div class="mascot-smile" style="border-bottom-color: var(--border);"></div>
</div>
<h3 class="mt-4" style="color: var(--text-muted);">Awaiting Instructions</h3>
<p style="max-width: 400px;">Fill out the Input Studio and click generate to create a comprehensive, IP-safe mascot system.</p>
</div>
<!-- Generated Content Area -->
<div id="generated-state" class="hidden" style="flex: 1;">
<!-- Mode Generators (Secondary Actions) -->
<div class="flex gap-2 mb-6 flex-wrap p-4 bg-gray-50 rounded-lg border border-gray-200 no-print" style="background: var(--bg); border-radius: var(--radius-md);">
<span style="font-size: 0.75rem; font-weight: 600; width: 100%; text-transform: uppercase; color: var(--text-muted);">Generate Specific Modes</span>
<button class="btn btn-secondary btn-small" id="btn-gen-variations">12 Variations</button>
<button class="btn btn-secondary btn-small" id="btn-gen-prompts">Prompt Pack</button>
<button class="btn btn-secondary btn-small" id="btn-gen-coloring">Coloring Book</button>
<button class="btn btn-secondary btn-small" id="btn-gen-brand">Brand Kit</button>
<button class="btn btn-secondary btn-small" id="btn-gen-story">Storybook</button>
<button class="btn btn-secondary btn-small" id="btn-gen-merch">Sticker/Merch</button>
</div>
<!-- Tabs -->
<div class="tabs no-print" id="output-tabs">
<button class="tab active" data-target="tab-system">Full System</button>
<button class="tab" data-target="tab-variations">Variations</button>
<button class="tab" data-target="tab-prompts">Prompt Pack</button>
<button class="tab" data-target="tab-coloring">Coloring Book</button>
<button class="tab" data-target="tab-brand">Brand Kit</button>
<button class="tab" data-target="tab-story">Storybook</button>
<button class="tab" data-target="tab-merch">Merch & Stickers</button>
</div>
<!-- Tab Contents -->
<div id="tab-system" class="tab-content active"></div>
<div id="tab-variations" class="tab-content"></div>
<div id="tab-prompts" class="tab-content"></div>
<div id="tab-coloring" class="tab-content"></div>
<div id="tab-brand" class="tab-content"></div>
<div id="tab-story" class="tab-content"></div>
<div id="tab-merch" class="tab-content"></div>
</div>
</div>
</main>
</main>
<footer class="container text-center mt-8 mb-4 no-print" style="font-size: 0.875rem; color: var(--text-muted);">
<p>ColoryMascot Studio · 100% Local Client-Side Processing · No External APIs Required</p>
</footer>
<!-- Global Loading Overlay -->
<div id="loading-overlay" class="hidden">
<div class="spinner"></div>
<h3 class="mt-4">Forging IP System...</h3>
<p id="loading-text">Applying safe margins and validating audience fit.</p>
</div>
<!-- Script Block -->
<script>
/**
* MascotVerse Forge Engine
* No external libraries. Pure Vanilla JS.
*/
// --- Data & State ---
const appState = {
inputs: {},
outputs: {
system: null,
variations: null,
prompts: null,
coloring: null,
brand: null,
story: null,
merch: null
},
score: 0,
activeTab: 'tab-system',
projects: []
};
const Dictionaries = {
bases: ['Fox', 'Bear', 'Robot', 'Cloud', 'Star', 'Cat', 'Dragon', 'Sloth', 'Mushroom', 'Alien', 'Ghost', 'Acorn', 'Bunny', 'Turtle', 'Owl'],
themes: ['Magic Forest', 'Space Station', 'Cozy Town', 'Underwater Reef', 'Candyland', 'Dino Park', 'Sky Castle', 'Steampunk City', 'Winter Village'],
personalities: ['Brave', 'Sleepy', 'Curious', 'Mischievous', 'Gentle', 'Energetic', 'Clumsy', 'Shy', 'Grumpy but sweet', 'Helpful'],
props: ['Star Wand', 'Oversized Hat', 'Paintbrush', 'Lantern', 'Backpack', 'Magnifying Glass', 'Teddy Bear', 'Scarf', 'Goggles', 'Book'],
protectedIPs: {
'disney': 'classic animated', 'marvel': 'heroic comic', 'star wars': 'sci-fi fantasy', 'pikachu': 'electric yellow companion',
'mickey': 'cheerful round-eared mascot', 'minnie': 'cheerful bow-wearing mascot', 'nintendo': 'retro gaming',
'mario': 'plumber hero', 'sonic': 'fast blue creature', 'peppa': 'friendly piglet', 'paw patrol': 'rescue pup',
'batman': 'dark vigilante', 'superman': 'caped hero', 'hello kitty': 'cute bow cat', 'spongebob': 'cheerful sea sponge',
'harry potter': 'student wizard', 'anime': 'expressive cartoon', 'pokemon': 'pocket monster'
}
};
// --- DOM Elements ---
const UI = {
form: document.getElementById('generator-form'),
baseType: document.getElementById('baseType'),
targetAudience: document.getElementById('targetAudience'),
useCase: document.getElementById('useCase'),
themeWorld: document.getElementById('themeWorld'),
personality: document.getElementById('personality'),
visualStyle: document.getElementById('visualStyle'),
signatureProp: document.getElementById('signatureProp'),
ipSafety: document.getElementById('ipSafety'),
emptyState: document.getElementById('empty-state'),
generatedState: document.getElementById('generated-state'),
scoreCircle: document.getElementById('quality-score'),
activeProjectName: document.getElementById('active-project-name'),
loader: document.getElementById('loading-overlay'),
tabs: document.querySelectorAll('.tab'),
tabContents: document.querySelectorAll('.tab-content'),
projectList: document.getElementById('project-list'),
projectCount: document.getElementById('project-count')
};
// --- Initialization ---
function init() {
loadProjectsFromStorage();
bindEvents();
}
function bindEvents() {
// Main Generate
document.getElementById('btn-generate-system').addEventListener('click', () => handleGenerate('system'));
// Specific Mode Generators
document.getElementById('btn-gen-variations').addEventListener('click', () => handleGenerate('variations'));
document.getElementById('btn-gen-prompts').addEventListener('click', () => handleGenerate('prompts'));
document.getElementById('btn-gen-coloring').addEventListener('click', () => handleGenerate('coloring'));
document.getElementById('btn-gen-brand').addEventListener('click', () => handleGenerate('brand'));
document.getElementById('btn-gen-story').addEventListener('click', () => handleGenerate('story'));
document.getElementById('btn-gen-merch').addEventListener('click', () => handleGenerate('merch'));
// Utilities
document.getElementById('btn-demo-data').addEventListener('click', loadDemoData);
document.getElementById('btn-randomize').addEventListener('click', randomizeInputs);
document.getElementById('btn-clear-form').addEventListener('click', () => UI.form.reset());
document.getElementById('btn-ip-check').addEventListener('click', runIPCheckWithUI);
document.getElementById('btn-scroll-gen').addEventListener('click', () => document.getElementById('generator-form').scrollIntoView({behavior: 'smooth'}));
// Export & Project
document.getElementById('btn-copy-active').addEventListener('click', copyActiveOutput);
document.getElementById('btn-export').addEventListener('click', handleExport);
document.getElementById('btn-save-project').addEventListener('click', saveCurrentProject);
document.getElementById('btn-clear-projects').addEventListener('click', clearProjects);
// Tabs
UI.tabs.forEach(tab => {
tab.addEventListener('click', () => switchTab(tab.dataset.target));
});
}
// --- Core Application Logic ---
function getFormData() {
return {
baseType: UI.baseType.value.trim(),
targetAudience: UI.targetAudience.value,
useCase: UI.useCase.value,
themeWorld: UI.themeWorld.value.trim() || 'A neutral studio background',
personality: UI.personality.value.trim() || 'Friendly',
visualStyle: UI.visualStyle.value,
signatureProp: UI.signatureProp.value.trim() || 'none',
ipSafety: UI.ipSafety.value
};
}
function loadDemoData() {
UI.baseType.value = "Chubby Mushroom";
UI.targetAudience.value = "Kids (Ages 5-10)";
UI.useCase.value = "Coloring Book (KDP)";
UI.themeWorld.value = "Enchanted Autumn Forest";
UI.personality.value = "Curious and slightly clumsy";
UI.visualStyle.value = "Thick Line Art (B&W)";
UI.signatureProp.value = "Oversized Oak Leaf Umbrella";
showToast("Demo Data Loaded!");
}
function randomizeInputs() {
const pick = arr => arr[Math.floor(Math.random() * arr.length)];
UI.baseType.value = pick(Dictionaries.bases);
UI.themeWorld.value = pick(Dictionaries.themes);
UI.personality.value = pick(Dictionaries.personalities);
UI.signatureProp.value = pick(Dictionaries.props);
showToast("Inputs Randomized!");
}
function sanitizeIP(text) {
if(!text) return text;
let sanitized = text.toLowerCase();
let triggered = false;
for (const [ip, safeTerm] of Object.entries(Dictionaries.protectedIPs)) {
const regex = new RegExp(`\\b${ip}\\b`, 'gi');
if (regex.test(sanitized)) {
sanitized = sanitized.replace(regex, safeTerm);
triggered = true;
}
}
return { text: sanitized, triggered };
}
function runIPCheckWithUI() {
const inputs = getFormData();
let triggered = false;
let checks = [UI.baseType, UI.themeWorld, UI.personality, UI.signatureProp];
checks.forEach(input => {
const result = sanitizeIP(input.value);
if(result.triggered) {
input.value = result.text;
triggered = true;
}
});
if(triggered) {
showToast("IP Risk Detected! Protected terms converted to safe traits.", 'warning');
} else {
showToast("IP Check Passed! 100% Safe.", 'success');
}
}
// --- Generators ---
async function handleGenerate(mode) {
if (!UI.form.checkValidity()) {
UI.form.reportValidity();
return;
}
// Run strict IP check silently
const checks = [UI.baseType, UI.themeWorld, UI.personality, UI.signatureProp];
checks.forEach(input => { input.value = sanitizeIP(input.value).text; });
appState.inputs = getFormData();
showLoader();
// Simulate processing time for UX
await new Promise(r => setTimeout(r, 600));
// Generate content based on mode
generateScore();
if (mode === 'system' || !appState.outputs.system) {
appState.outputs.system = generateSystemText(appState.inputs);
}
if (mode === 'variations') appState.outputs.variations = generateVariationsText(appState.inputs);
if (mode === 'prompts') appState.outputs.prompts = generatePromptsText(appState.inputs);
if (mode === 'coloring') appState.outputs.coloring = generateColoringText(appState.inputs);
if (mode === 'brand') appState.outputs.brand = generateBrandText(appState.inputs);
if (mode === 'story') appState.outputs.story = generateStoryText(appState.inputs);
if (mode === 'merch') appState.outputs.merch = generateMerchText(appState.inputs);
hideLoader();
renderOutputs();
switchTab(`tab-${mode}`);
UI.emptyState.classList.add('hidden');
UI.generatedState.classList.remove('hidden');
showToast(`${mode.toUpperCase()} Generated Successfully!`);
}
function generateScore() {
let score = 100;
const i = appState.inputs;
if(!i.themeWorld || i.themeWorld.length < 3) score -= 10;
if(!i.personality || i.personality.length < 3) score -= 10;
if(i.signatureProp === 'none') score -= 5;
// Check audience match complexity
if (i.targetAudience.includes("Preschool") && i.visualStyle !== "Thick Line Art (B&W)") score -= 15;
appState.score = Math.max(0, score);
UI.scoreCircle.innerText = appState.score;
// Color coding
if(score > 85) UI.scoreCircle.style.borderColor = "var(--success)";
else if(score > 60) UI.scoreCircle.style.borderColor = "var(--warning)";
else UI.scoreCircle.style.borderColor = "var(--danger)";
}
// --- Text Building Engines ---
const audienceRules = {
"Preschool (Ages 3-5)": "Extremely simple shapes, no small details, ultra-thick lines, highly clear silhouette.",
"Kids (Ages 5-10)": "Fun expressions, engaging props, clean thick lines, medium detail for coloring.",
"Middle School": "Edgier or more detailed line art, dynamic poses, deeper lore.",
"Parents & Families": "Wholesome, safe, universally appealing, highly commercial.",
"Teachers & Classrooms": "Educational styling, friendly, clear subjects, space for text.",
"General Commercial Buyers": "Premium vector quality, highly brandable, scalable, perfectly symmetric options."
};
function getAudienceRule(aud) {
return audienceRules[aud] || audienceRules["General Commercial Buyers"];
}
function generateSystemText(i) {
const rule = getAudienceRule(i.targetAudience);
return `
<div class="output-block">
<h4>1. Research Brief</h4>
<p><strong>Target Audience Fit:</strong> ${i.targetAudience}. Logic: ${rule}</p>
<p><strong>Commercial Goal:</strong> Optimized for ${i.useCase}.</p>
<p><strong>Originality Check:</strong> Verified IP-Safe. Transformed into neutral archetype traits.</p>
</div>
<div class="output-block">
<h4>2. Mascot Concept Snapshot</h4>
<div class="output-text">Name Concept: "Pip the ${i.baseType}" (Placeholder)
Core Identity: A ${i.personality} ${i.baseType} living in ${i.themeWorld}.
Visual Hook: Instantly recognizable by their ${i.signatureProp}.
Style Mandate: ${i.visualStyle}</div>
</div>
<div class="output-block">
<h4>3. Visual Consistency Bible</h4>
<p>To keep the character looking identical across different AI generations or illustrator briefs, enforce these rules strictly:</p>
<ul>
<li><strong>Proportions:</strong> Head-to-body ratio must remain 1:1 (large head, small body) to maintain cuteness.</li>
<li><strong>Silhouette:</strong> The outline must clearly show a ${i.baseType} shape, even if fully blacked out.</li>
<li><strong>The Anchor Prop:</strong> The ${i.signatureProp} MUST be present in at least 80% of generations to ground the identity.</li>
<li><strong>Line Weight:</strong> Maintain consistent thick outlines for coloring applications.</li>
</ul>
</div>
<div class="output-block">
<h4>4. Commercial Use Ideas</h4>
<ul>
<li><strong>Primary:</strong> Full page ${i.useCase} featuring the character.</li>
<li><strong>Secondary:</strong> Die-cut stickers for Etsy featuring the face only.</li>
<li><strong>Tertiary:</strong> Cover design featuring the character fully colored as an example.</li>
</ul>
</div>
`;
}
function generateVariationsText(i) {
let html = `<div class="output-block"><h4>12 Market-Tested Variations</h4><div class="grid grid-cols-12 gap-4">`;
const pick = arr => arr[Math.floor(Math.random() * arr.length)];
for(let j=1; j<=12; j++) {
const trait = pick(Dictionaries.personalities);
const prop = pick(Dictionaries.props);
html += `
<div class="col-span-4" style="border:1px solid var(--border); padding: 1rem; border-radius: var(--radius-md);">
<strong>Var ${j}: The ${trait} ${i.baseType}</strong>
<p style="font-size:0.75rem; margin-top:0.5rem; margin-bottom:0;">Hook: Holding a ${prop}</p>
</div>`;
}
html += `</div></div>`;
return html;
}
function generatePromptsText(i) {
const basePrompt = `White background, full body character, centered subject, safe margin, no cropped body parts. ${i.visualStyle} style illustration of a cute ${i.personality} ${i.baseType}. ${i.signatureProp !== 'none' ? `The character is holding/wearing a ${i.signatureProp}.` : ''} Theme: ${i.themeWorld}.`;
const audRule = getAudienceRule(i.targetAudience);
return `
<div class="output-block">
<h4>Copy-Ready AI Image Prompts</h4>
<p>Optimized for Midjourney, DALL-E 3, and Stable Diffusion.</p>
<strong>1. Hero Cover Image (Colored)</strong>
<div class="output-text mb-4">${basePrompt} Vibrant flat colors, 2d vector art, premium commercial illustration, no shading. --ar 4:5</div>
<strong>2. Standard Coloring Page</strong>
<div class="output-text mb-4">${basePrompt} Pure black and white line art, thick clean outlines, no grayscale, no shading, minimal intersecting lines, easy to color. ${audRule} --ar 8:11</div>
<strong>3. Sticker Sheet Generation</strong>
<div class="output-text mb-4">Sticker sheet layout, white border around characters. Multiple poses of a cute ${i.personality} ${i.baseType} with a ${i.signatureProp}. Flat vector style, clean white background, evenly spaced. --ar 3:2</div>
<strong>4. Action Pose (Jumping)</strong>
<div class="output-text mb-4">${basePrompt} The character is jumping happily in the air. Dynamic pose. Pure black and white line art, thick outlines. --ar 1:1</div>
<strong>Negative Prompt (Append to all)</strong>
<div class="output-text">ugly, deformed, cropped, out of frame, grayscale, shading, gradients, messy lines, text, watermark, signature, realistic, 3d, complex background</div>
</div>
`;
}
function generateColoringText(i) {
const rule = getAudienceRule(i.targetAudience);
return `
<div class="output-block">
<h4>Strict Coloring Book Mode</h4>
<p>This mode formats the IP specifically for KDP and printable creators. Copy the prompt block below directly into your AI generator.</p>
<div class="output-text" style="font-size: 1rem; padding: 1.5rem; border-color: var(--primary);">
<strong>[SYSTEM DIRECTIVE: STRICT BLACK AND WHITE COLORING PAGE]</strong>
<strong>Subject:</strong> A full body, centered ${i.personality} ${i.baseType} character.
<strong>Prop:</strong> Must include a ${i.signatureProp}.
<strong>Environment:</strong> ${i.themeWorld} elements in the background, but kept extremely simple and non-distracting.
<strong>Style:</strong> Thick, bold, pure black continuous outlines.
<strong>Background:</strong> Pure #FFFFFF white background.
<strong>Exclusions:</strong> NO shading. NO hatching. NO stippling. NO grayscale. NO gradients. NO complex textures. NO cropped body parts.
<strong>Audience Adaptation:</strong> ${rule}
<strong>Composition:</strong> Ensure a 10% safe margin around the entire character so it is not cut off during printing.
</div>
</div>
`;
}
function generateBrandText(i) {
return `
<div class="output-block">
<h4>Brand Kit & Packaging Mode</h4>
<p><strong>Brand Voice:</strong> ${i.personality}, approachable, and perfect for ${i.targetAudience}.</p>
<p><strong>Color Palette Suggestion:</strong></p>
<div class="flex gap-2 mb-4">
<div style="width: 40px; height: 40px; border-radius: 50%; background: #0f172a;" title="Primary Ink"></div>
<div style="width: 40px; height: 40px; border-radius: 50%; background: #ffffff; border: 1px solid #ccc;" title="Paper White"></div>
<div style="width: 40px; height: 40px; border-radius: 50%; background: #3b82f6;" title="Brand Accent"></div>
<div style="width: 40px; height: 40px; border-radius: 50%; background: #f59e0b;" title="Warm Highlight"></div>
</div>
<strong>Typography Pairing (System Safe):</strong>
<p>Header: <em>Arial Rounded MT Bold</em> or <em>Nunito</em><br>Body: <em>Verdana</em> or <em>Quicksand</em></p>
<strong>Slogan Ideas:</strong>
<ul>
<li>"Colors of the ${i.themeWorld}!"</li>
<li>"Your ${i.personality} friend, ready to color!"</li>
</ul>
<strong>Packaging Integration:</strong>
<p>Place the ${i.baseType} on the bottom right corner of the printable bundle cover, looking up and pointing at the title, holding the ${i.signatureProp}.</p>
</div>
`;
}
function generateStoryText(i) {
return `
<div class="output-block">
<h4>Storybook Framework</h4>
<p>A quick 6-scene narrative for ${i.targetAudience}.</p>
<div class="grid grid-cols-12 gap-4">
<div class="col-span-12 card" style="padding: 1rem;">
<strong>1. The Opening:</strong> The ${i.baseType} wakes up in the ${i.themeWorld}, feeling very ${i.personality}.
</div>
<div class="col-span-12 card" style="padding: 1rem;">
<strong>2. The Problem:</strong> They drop their beloved ${i.signatureProp} and it rolls away!
</div>
<div class="col-span-12 card" style="padding: 1rem;">
<strong>3. The Discovery:</strong> While searching, they find a blank, colorless area of the world.
</div>
<div class="col-span-12 card" style="padding: 1rem;">
<strong>4. The Turning Point:</strong> Using the ${i.signatureProp}, they realize they can bring color back to the area.
</div>
<div class="col-span-12 card" style="padding: 1rem;">
<strong>5. The Climax:</strong> A giant, friendly puzzle needs solving using colors. (Interactive coloring page).
</div>
<div class="col-span-12 card" style="padding: 1rem;">
<strong>6. The Closing:</strong> The ${i.baseType} goes to sleep, the world colorful and bright.
</div>
</div>
</div>
`;
}
function generateMerchText(i) {
return `
<div class="output-block">
<h4>Sticker & Merch Mode</h4>
<p>Optimized for die-cut stickers and Redbubble/Etsy products.</p>
<strong>12 Sticker Pose Ideas:</strong>
<div class="output-text mb-4">
1. Waving hello
2. Sleeping cutely
3. Hugging the ${i.signatureProp}
4. Peeking over a wall
5. Jumping with joy
6. Looking confused/curious
7. Sitting down eating
8. Wearing sunglasses (Cool mode)
9. Running fast
10. Holding a blank sign (for sellers to add text)
11. Tangled up playfully
12. Looking at a butterfly
</div>
<strong>T-Shirt Concept:</strong>
<p>Center chest placement. The ${i.baseType} inside a thick circular border featuring elements of the ${i.themeWorld}. Text wrap around border: "Stay ${i.personality}!"</p>
</div>
`;
}
// --- Render & UI Updates ---
function renderOutputs() {
if(!appState.outputs.system) return;
document.getElementById('tab-system').innerHTML = appState.outputs.system || '';
document.getElementById('tab-variations').innerHTML = appState.outputs.variations || '<div class="output-block"><p>Click the "12 Variations" button to generate.</p></div>';
document.getElementById('tab-prompts').innerHTML = appState.outputs.prompts || '<div class="output-block"><p>Click the "Prompt Pack" button to generate.</p></div>';
document.getElementById('tab-coloring').innerHTML = appState.outputs.coloring || '<div class="output-block"><p>Click the "Coloring Book" button to generate.</p></div>';
document.getElementById('tab-brand').innerHTML = appState.outputs.brand || '<div class="output-block"><p>Click the "Brand Kit" button to generate.</p></div>';
document.getElementById('tab-story').innerHTML = appState.outputs.story || '<div class="output-block"><p>Click the "Storybook" button to generate.</p></div>';
document.getElementById('tab-merch').innerHTML = appState.outputs.merch || '<div class="output-block"><p>Click the "Sticker/Merch" button to generate.</p></div>';
}
function switchTab(targetId) {
appState.activeTab = targetId;
UI.tabs.forEach(t => t.classList.remove('active'));
UI.tabContents.forEach(c => c.classList.remove('active'));
document.querySelector(`[data-target="${targetId}"]`).classList.add('active');
document.getElementById(targetId).classList.add('active');
}
// --- Utilities & Exports ---
function showLoader() {
UI.loader.classList.remove('hidden');
}
function hideLoader() {
UI.loader.classList.add('hidden');
}
function showToast(message, type = 'success') {
const toast = document.createElement('div');
toast.className = `toast ${type === 'warning' ? 'warning' : ''}`;
if(type === 'warning') {
toast.style.background = 'var(--warning)';
toast.style.color = '#000';
}
toast.innerText = message;
document.body.appendChild(toast);
setTimeout(() => {
toast.style.opacity = '0';
setTimeout(() => toast.remove(), 300);
}, 3000);
}
function copyActiveOutput() {
const content = document.getElementById(appState.activeTab).innerText;
if(!content.trim()) return showToast('Nothing to copy!', 'warning');
navigator.clipboard.writeText(content).then(() => {
showToast('Copied to clipboard!');
}).catch(() => {
// Fallback for Canvas iframe
const textArea = document.createElement("textarea");
textArea.value = content;
document.body.appendChild(textArea);
textArea.select();
document.execCommand("copy");
textArea.remove();
showToast('Copied to clipboard!');
});
}
function handleExport() {
const format = document.getElementById('exportFormat').value;
const dataStr = gatherAllOutputText();
const filename = `MascotVerse_${appState.inputs.baseType || 'Project'}`;
if(format === 'pdf') {
window.print();
return;
}
let blob, url;
if(format === 'txt') {
blob = new Blob([dataStr], { type: 'text/plain' });
} else if (format === 'json') {
blob = new Blob([JSON.stringify({inputs: appState.inputs, outputs: appState.outputs}, null, 2)], { type: 'application/json' });
} else if (format === 'html') {
const htmlContent = `<html><body><h1>${filename}</h1><pre>${dataStr}</pre></body></html>`;
blob = new Blob([htmlContent], { type: 'text/html' });
}
url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${filename}.${format}`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
showToast(`Downloaded as .${format.toUpperCase()}`);
}
function gatherAllOutputText() {
let str = "MASCOTVERSE EXPORT\n\n";
Object.keys(appState.outputs).forEach(key => {
if(appState.outputs[key]) {
// Quick strip HTML tags for clean text export
let text = appState.outputs[key].replace(/<[^>]+>/g, '\n').replace(/\n\s*\n/g, '\n\n').trim();
str += `--- ${key.toUpperCase()} ---\n${text}\n\n`;
}
});
return str;
}
// --- Local Storage Project Manager ---
function loadProjectsFromStorage() {
try {
const saved = localStorage.getItem('mascotVerseProjects');
if(saved) {
appState.projects = JSON.parse(saved);
}
} catch(e) {
console.error("Storage access error");
}
renderProjectList();
}
function saveCurrentProject() {
if(!appState.outputs.system) {
showToast("Generate a project first before saving.", "warning");
return;
}
const projName = `${appState.inputs.personality} ${appState.inputs.baseType}`;
const proj = {
id: Date.now(),
name: projName,
date: new Date().toLocaleDateString(),
inputs: { ...appState.inputs },
outputs: { ...appState.outputs },
score: appState.score
};
appState.projects.push(proj);
try {
localStorage.setItem('mascotVerseProjects', JSON.stringify(appState.projects));
UI.activeProjectName.innerText = projName;
showToast("Project Saved Locally!");
renderProjectList();
} catch(e) {
showToast("Failed to save. Storage might be full or restricted.", "warning");
}
}
function renderProjectList() {
UI.projectCount.innerText = appState.projects.length;
if(appState.projects.length === 0) {
UI.projectList.innerHTML = '<p class="text-center" style="font-size: 0.875rem; color: var(--text-muted);">No saved projects.</p>';
return;
}
UI.projectList.innerHTML = '';
appState.projects.slice().reverse().forEach(p => {
const item = document.createElement('div');
item.className = 'card flex justify-between items-center';
item.style.padding = '0.5rem';
item.style.borderWidth = '1px';
item.innerHTML = `
<div style="flex:1; cursor:pointer;" class="load-proj" data-id="${p.id}">
<div style="font-weight:600; font-size:0.875rem;">${p.name}</div>
<div style="font-size:0.75rem; color:var(--text-muted);">${p.date} | Score: ${p.score}</div>
</div>
<button class="btn btn-danger btn-small del-proj" data-id="${p.id}" title="Delete">✕</button>
`;
UI.projectList.appendChild(item);
});
// Bind load/delete
document.querySelectorAll('.load-proj').forEach(el => {
el.addEventListener('click', (e) => {
if(e.target.closest('.del-proj')) return;
loadProjectById(parseInt(el.dataset.id));
});
});
document.querySelectorAll('.del-proj').forEach(el => {
el.addEventListener('click', (e) => {
deleteProject(parseInt(el.dataset.id));
});
});
}
function loadProjectById(id) {
const proj = appState.projects.find(p => p.id === id);
if(!proj) return;
appState.inputs = proj.inputs;
appState.outputs = proj.outputs;
appState.score = proj.score;
// Re-populate form
UI.baseType.value = proj.inputs.baseType;
UI.targetAudience.value = proj.inputs.targetAudience;
UI.useCase.value = proj.inputs.useCase;
UI.themeWorld.value = proj.inputs.themeWorld;
UI.personality.value = proj.inputs.personality;
UI.visualStyle.value = proj.inputs.visualStyle;
UI.signatureProp.value = proj.inputs.signatureProp;
UI.ipSafety.value = proj.inputs.ipSafety || 'Strict';
UI.scoreCircle.innerText = appState.score;
UI.activeProjectName.innerText = proj.name;
UI.emptyState.classList.add('hidden');
UI.generatedState.classList.remove('hidden');
renderOutputs();
showToast("Project Loaded!");
}
function deleteProject(id) {
appState.projects = appState.projects.filter(p => p.id !== id);
localStorage.setItem('mascotVerseProjects', JSON.stringify(appState.projects));
renderProjectList();
showToast("Project Deleted");
}
function clearProjects() {
if(confirm("Are you sure you want to delete all saved projects locally?")) {
appState.projects = [];
localStorage.removeItem('mascotVerseProjects');
renderProjectList();
showToast("All Projects Cleared");
}
}
// Start App
document.addEventListener('DOMContentLoaded', init);
</script>
</body>
</html>
By purchasing this prompt, you agree to our terms of service
GEMINI-3.1-PRO
Gemini mascot generator web app from simple inputs. No coding skill or special setup needed.
...more
Added 1 week ago
