Skip to main content
Glama
character-consistency.js22.4 kB
// Character Consistency and Template System for Puppet Productions // Provides size references, template prompts, and character trait management export class CharacterConsistencyManager { constructor() { this.sizeReferences = this.initializeSizeReferences(); this.templatePrompts = this.initializeTemplatePrompts(); this.puppetTraitCategories = this.initializePuppetTraits(); } // Standard size reference system recognized by AI generators initializeSizeReferences() { return { // Puppet size categories with specific measurements sizes: { 'tiny': { description: 'Small hand puppet, child-sized', measurements: '12-18 inches tall, hand-held scale', referenceObjects: 'size of a large book, fits in adult hands', headToBodyRatio: '1:2', avgWeight: '8-12 ounces' }, 'small': { description: 'Standard hand puppet, compact performer', measurements: '18-24 inches tall, desktop scale', referenceObjects: 'size of a laptop computer, tabletop height', headToBodyRatio: '1:2.5', avgWeight: '1-2 pounds' }, 'medium': { description: 'Full-size puppet, standard performer', measurements: '30-36 inches tall, waist-high scale', referenceObjects: 'height of a kitchen counter, adult waist-high', headToBodyRatio: '1:3', avgWeight: '3-5 pounds' }, 'large': { description: 'Stage puppet, prominent character', measurements: '42-48 inches tall, chest-high scale', referenceObjects: 'height of a dining table, adult chest-high', headToBodyRatio: '1:3.5', avgWeight: '6-10 pounds' }, 'giant': { description: 'Feature puppet, dominant presence', measurements: '54-60 inches tall, adult shoulder height', referenceObjects: 'height of a standard door, adult shoulder-high', headToBodyRatio: '1:4', avgWeight: '12-20 pounds' } }, // Standard reference objects for scale consistency referenceObjects: { 'coin': 'US quarter (24.26mm diameter)', 'hand': 'adult human hand (7.5 inches length)', 'smartphone': 'iPhone standard size (5.8 x 2.8 inches)', 'book': 'paperback book (7.5 x 4.25 inches)', 'mug': 'coffee mug (4 inches tall, 3.5 inches diameter)', 'ruler': '12-inch standard ruler', 'doorframe': 'standard door frame (80 inches tall, 36 inches wide)', 'table': 'dining table (30 inches height)', 'chair': 'standard chair (32 inches back height, 18 inches seat)' }, // Resolution standards for different outputs resolutions: { 'draft': '1024x1024px (1:1), 512x768px (2:3)', 'standard': '1536x1536px (1:1), 1024x1536px (2:3)', 'professional': '2048x2048px (1:1), 1365x2048px (2:3)', 'print': '3000x3000px (1:1), 2000x3000px (2:3)', 'cinema': '3840x2160px (16:9), 2560x1440px (16:9)' } }; } // Comprehensive template prompt system initializeTemplatePrompts() { return { // Base puppet construction template basePuppetTemplate: { core: 'realistic puppet character, professional Muppet-style construction', framing: 'waist-up view, {VIEW_ANGLE}', background: 'solid black contrasting background, studio lighting', quality: 'high quality 4K puppet photography, sharp focus' }, // Character creation templates characterCreation: { establishingShot: `{CHARACTER_SIZE} hand puppet character with visible control rods, {CHARACTER_DESCRIPTION}, {SKIN_TONE_ACCURATE} felt fabric skin matching reference person exactly, {HAIR_COLOR_ACCURATE} hair replicating reference person, {FACIAL_FEATURES_ACCURATE} face shape and features proportioned to match reference person, {DEFINING_FEATURES}, {CONSTRUCTION_DETAILS}, two-person operation capable with finger articulation, front view facing camera, {EMOTION_STATE}, professional puppet photography, solid black background, studio lighting, {SCALE_REFERENCE}`, profileViews: `{CHARACTER_SIZE} hand puppet character with visible control rods, {CHARACTER_DESCRIPTION}, {SKIN_TONE_ACCURATE} felt fabric skin matching reference person exactly, {HAIR_COLOR_ACCURATE} hair color, {FACIAL_FEATURES_ACCURATE} face structure maintaining reference person's proportions, {DEFINING_FEATURES}, {CONSTRUCTION_DETAILS}, {VIEW_ANGLE}, neutral expression, consistent character design from front view, two-person operable, solid black background, studio lighting, {SCALE_REFERENCE}`, emotionalExpressions: `{CHARACTER_SIZE} hand puppet character with visible control rods, {CHARACTER_DESCRIPTION}, {SKIN_TONE_ACCURATE} felt fabric skin matching reference person exactly, {HAIR_COLOR_ACCURATE} hair, {FACIAL_FEATURES_ACCURATE} facial features replicating reference person's structure, {DEFINING_FEATURES}, {CONSTRUCTION_DETAILS}, front view facing camera, {EMOTION_STATE} expression, {EMOTION_SPECIFIC_DETAILS}, individual finger articulation visible, solid black background, studio lighting, {SCALE_REFERENCE}` }, // Scene production templates sceneProduction: { characterInScene: `{CHARACTER_SIZE} puppet character named {CHARACTER_NAME}, {CHARACTER_DESCRIPTION}, {DEFINING_FEATURES}, {CONSTRUCTION_DETAILS}, {SCENE_POSITION}, {CHARACTER_ACTION}, {EMOTION_STATE}, {SCENE_DESCRIPTION}, {LIGHTING_SETUP}, {SCALE_REFERENCE}`, multiCharacterScene: `Multiple puppet characters in scene: {CHARACTER_LIST}, each maintaining their established size ratios and features, {SCENE_DESCRIPTION}, {CHARACTER_INTERACTIONS}, {LIGHTING_SETUP}, consistent scale relationships, {SCALE_REFERENCE}`, characterAction: `{CHARACTER_SIZE} puppet character {CHARACTER_NAME}, {CHARACTER_DESCRIPTION}, {DEFINING_FEATURES}, {CONSTRUCTION_DETAILS}, performing action: {ACTION_DESCRIPTION}, {MOVEMENT_STYLE}, {EMOTION_STATE}, {SCENE_CONTEXT}, {SCALE_REFERENCE}` }, // Consistency enforcement rules consistencyRules: { mandatoryElements: [ 'hand puppet construction with visible control rods (NO string puppet/marionette)', 'accurate skin tone fabric matching reference person', 'hair color and style replicating reference person exactly', 'facial features proportioned to match reference person', 'felt/foam texture with professional puppet construction', 'mechanical mouth operation with hand control', 'individual finger articulation capability', 'two-person operation capability with rod controls', 'consistent character features across all views and expressions', 'solid black contrasting background', 'waist-up framing showing puppet construction', 'studio lighting setup', 'scale reference object present' ], prohibitedElements: [ 'string puppet/marionette construction', 'generic puppet skin color (must match reference person)', 'inaccurate hair color (must match reference exactly)', 'cartoon or animation style rendering', 'inconsistent scale or proportions', 'background elements that distract from puppet', 'natural human skin textures on puppet', 'unrealistic eye movement', 'clothing that doesn\'t reflect person\'s style', 'puppet hanging from strings or wires', 'overly simplified facial features' ] } }; } // Puppet trait categories for database storage initializePuppetTraits() { return { physicalTraits: { size: ['tiny', 'small', 'medium', 'large', 'giant'], construction: ['felt', 'foam', 'fur', 'fleece', 'mixed_materials'], headShape: ['round', 'oval', 'angular', 'elongated', 'wide'], eyeType: ['button', 'plastic', 'fabric', 'ping_pong', 'custom'], mouthType: ['basic_opening', 'articulated_jaw', 'simple_slit', 'complex_mechanical'], hairFur: ['synthetic_hair', 'wool', 'fur_fabric', 'yarn', 'feathers', 'bald'], handType: ['simple_mittens', 'articulated_fingers', 'rod_controlled', 'glove_style'] }, movementTraits: { eyeMovement: ['fixed_position', 'limited_side_to_side', 'full_mechanical', 'blink_capable'], mouthMovement: ['simple_open_close', 'jaw_articulation', 'tongue_visible', 'teeth_visible'], headMovement: ['basic_turn', 'full_rotation', 'tilt_capable', 'nod_shake'], bodyMovement: ['static_pose', 'arm_articulation', 'torso_bend', 'full_puppeteer_control'], handMovement: ['basic_positioning', 'finger_articulation', 'grip_capable', 'gesture_specific'] }, personalityTraits: { energyLevel: ['low_energy', 'moderate', 'high_energy', 'hyperactive'], movementStyle: ['bouncy_muppet', 'smooth_gliding', 'jerky_mechanical', 'flowing_graceful'], voiceMatch: ['high_pitched', 'deep_resonant', 'raspy_textured', 'smooth_melodic'], characterArchetype: ['hero', 'comic_relief', 'wise_mentor', 'villain', 'innocent', 'quirky'] } }; } // Generate size-specific prompt with reference objects buildSizePrompt(characterSize, includeReference = true) { const sizeData = this.sizeReferences.sizes[characterSize]; if (!sizeData) return ''; let prompt = `${sizeData.description}, ${sizeData.measurements}`; if (includeReference) { prompt += `, scale reference: ${sizeData.referenceObjects}`; } return prompt; } // Generate character-specific prompt from database traits buildCharacterPrompt(characterTraits, promptType, templateVariables = {}) { const template = this.templatePrompts.characterCreation[promptType]; if (!template) throw new Error(`Unknown prompt type: ${promptType}`); // Build character description from traits const description = this.buildCharacterDescription(characterTraits); const definingFeatures = this.buildDefiningFeatures(characterTraits); const constructionDetails = this.buildConstructionDetails(characterTraits); const scaleReference = this.buildSizePrompt(characterTraits.size || 'medium'); // Build enhanced feature variables for accurate replication const skinToneAccurate = this.extractSkinToneDetails(characterTraits); const hairColorAccurate = this.extractHairDetails(characterTraits); const facialFeaturesAccurate = this.extractFacialFeatures(characterTraits); // Replace template variables including enhanced physical features let prompt = template .replace('{CHARACTER_SIZE}', this.buildSizePrompt(characterTraits.size || 'medium', false)) .replace('{CHARACTER_DESCRIPTION}', description) .replace('{DEFINING_FEATURES}', definingFeatures) .replace('{CONSTRUCTION_DETAILS}', constructionDetails) .replace('{SCALE_REFERENCE}', scaleReference) .replace('{SKIN_TONE_ACCURATE}', skinToneAccurate) .replace('{HAIR_COLOR_ACCURATE}', hairColorAccurate) .replace('{FACIAL_FEATURES_ACCURATE}', facialFeaturesAccurate); // Replace any additional variables Object.entries(templateVariables).forEach(([key, value]) => { prompt = prompt.replace(`{${key}}`, value); }); // Add consistency rules const mandatoryElements = this.templatePrompts.consistencyRules.mandatoryElements.join(', '); const negativeElements = this.templatePrompts.consistencyRules.prohibitedElements.join(', '); return { positive: `${prompt}, ${mandatoryElements}`, negative: negativeElements }; } // Build detailed character description from traits buildCharacterDescription(traits) { const parts = []; // Enhanced physical replication from Claude analysis if (traits.physical_replication?.build_type) parts.push(traits.physical_replication.build_type); if (traits.age) parts.push(`${traits.age} years old`); if (traits.gender) parts.push(traits.gender); // Legacy support if (traits.species) parts.push(traits.species); if (traits.primaryColor) parts.push(`primary color ${traits.primaryColor}`); if (traits.secondaryColor) parts.push(`secondary color ${traits.secondaryColor}`); return parts.length > 0 ? parts.join(', ') : 'puppet character'; } // Build defining physical features buildDefiningFeatures(traits) { const features = []; // Enhanced physical replication features from Claude analysis if (traits.physical_replication?.eye_characteristics) { features.push(traits.physical_replication.eye_characteristics); } if (traits.physical_replication?.facial_structure) { features.push(traits.physical_replication.facial_structure); } if (traits.physical_replication?.distinctive_features?.length > 0) { features.push(...traits.physical_replication.distinctive_features); } // Legacy support if (traits.eyeColor) features.push(`${traits.eyeColor} eyes`); if (traits.eyeType) features.push(`${traits.eyeType} eye construction`); if (traits.hairFur) features.push(`${traits.hairFur} hair/fur`); if (traits.specialMarkings) features.push(traits.specialMarkings); if (traits.clothing) features.push(`wearing ${traits.clothing}`); return features.length > 0 ? features.join(', ') : 'standard puppet features'; } // Build construction-specific details buildConstructionDetails(traits) { const construction = []; // Enhanced puppet construction from Claude analysis if (traits.puppet_construction_specs?.puppet_type) { construction.push(traits.puppet_construction_specs.puppet_type); } if (traits.puppet_construction_specs?.hand_operation) { construction.push(traits.puppet_construction_specs.hand_operation); } if (traits.puppet_construction_specs?.material_specifications) { construction.push(traits.puppet_construction_specs.material_specifications); } if (traits.puppet_construction_specs?.articulation_points?.length > 0) { construction.push(`articulation: ${traits.puppet_construction_specs.articulation_points.join(', ')}`); } // Legacy support if (traits.construction) construction.push(`${traits.construction} puppet construction`); if (traits.mouthType) construction.push(`${traits.mouthType} mouth mechanism`); if (traits.handType) construction.push(`${traits.handType} hand design`); if (traits.movementStyle) construction.push(`${traits.movementStyle} movement style`); return construction.length > 0 ? construction.join(', ') : 'standard hand puppet with rod controls'; } // Extract accurate skin tone details from character traits extractSkinToneDetails(traits) { // First priority: Enhanced physical replication data from Claude if (traits.physical_replication?.skin_tone) { return traits.physical_replication.skin_tone + ' fabric puppet skin'; } // Legacy fallback: physical_consistency schema if (traits.physical_consistency?.skin_tone) { return traits.physical_consistency.skin_tone + ' fabric puppet skin'; } // Basic fallback: use primary color if available if (traits.primaryColor) { return `${traits.primaryColor} puppet skin`; } return 'standard felt puppet skin tone'; } // Extract accurate hair details from character traits extractHairDetails(traits) { // First priority: Enhanced physical replication data from Claude if (traits.physical_replication?.hair_replication) { return traits.physical_replication.hair_replication + ' synthetic puppet hair'; } // Legacy fallback: physical_consistency schema if (traits.physical_consistency?.hair_details) { return traits.physical_consistency.hair_details + ' puppet hair'; } // Basic fallback: use hair/fur trait if (traits.hairFur) { return `${traits.hairFur} puppet hair`; } return 'standard synthetic puppet hair'; } // Extract accurate facial features from character traits extractFacialFeatures(traits) { // First priority: Enhanced physical replication data from Claude if (traits.physical_replication?.facial_structure) { return traits.physical_replication.facial_structure + ' replicated in puppet form'; } // Legacy fallback: physical_consistency schema if (traits.physical_consistency?.facial_features) { return traits.physical_consistency.facial_features + ' puppet construction'; } // Basic fallback: build from individual traits const features = []; if (traits.eyeColor) features.push(`${traits.eyeColor} puppet eyes`); if (traits.eyeType) features.push(`${traits.eyeType} eye construction`); return features.length > 0 ? features.join(', ') : 'standard puppet facial proportions'; } // Generate scene prompt maintaining character consistency buildScenePrompt(characters, sceneDescription, templateVariables = {}) { if (characters.length === 1) { const character = characters[0]; const template = this.templatePrompts.sceneProduction.characterInScene; let prompt = template .replace('{CHARACTER_SIZE}', this.buildSizePrompt(character.traits.size || 'medium', false)) .replace('{CHARACTER_NAME}', character.name) .replace('{CHARACTER_DESCRIPTION}', this.buildCharacterDescription(character.traits)) .replace('{DEFINING_FEATURES}', this.buildDefiningFeatures(character.traits)) .replace('{CONSTRUCTION_DETAILS}', this.buildConstructionDetails(character.traits)) .replace('{SCENE_DESCRIPTION}', sceneDescription) .replace('{SCALE_REFERENCE}', this.buildSizePrompt(character.traits.size || 'medium')); // Replace additional variables Object.entries(templateVariables).forEach(([key, value]) => { prompt = prompt.replace(`{${key}}`, value); }); return prompt; } else { // Multi-character scene logic const characterList = characters.map(char => `${char.name} (${this.buildSizePrompt(char.traits.size || 'medium', false)})` ).join(', '); const template = this.templatePrompts.sceneProduction.multiCharacterScene; let prompt = template .replace('{CHARACTER_LIST}', characterList) .replace('{SCENE_DESCRIPTION}', sceneDescription); Object.entries(templateVariables).forEach(([key, value]) => { prompt = prompt.replace(`{${key}}`, value); }); return prompt; } } // Validate prompt consistency validatePrompt(prompt) { const required = this.templatePrompts.consistencyRules.mandatoryElements; const prohibited = this.templatePrompts.consistencyRules.prohibitedElements; const validation = { isValid: true, missing: [], violations: [] }; // Check for required elements required.forEach(element => { if (!prompt.toLowerCase().includes(element.toLowerCase())) { validation.missing.push(element); validation.isValid = false; } }); // Check for prohibited elements prohibited.forEach(element => { if (prompt.toLowerCase().includes(element.toLowerCase())) { validation.violations.push(element); validation.isValid = false; } }); return validation; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bermingham85/mcp-puppet-pipeline'

If you have feedback or need assistance with the MCP directory API, please join our Discord server