// Database Schema Enhancement for Character Trait Storage
// Enhances Notion database with comprehensive character consistency fields
export class DatabaseSchemaEnhancer {
constructor(notionClient) {
this.notion = notionClient;
this.characterTraitFields = this.defineCharacterTraitFields();
}
// Define comprehensive character trait fields for Notion database
defineCharacterTraitFields() {
return {
// Physical Characteristics
physicalTraits: {
'Character Size': {
type: 'select',
options: ['tiny', 'small', 'medium', 'large', 'giant'],
description: 'Puppet size category with specific measurements'
},
'Construction Material': {
type: 'select',
options: ['felt', 'foam', 'fur', 'fleece', 'mixed_materials'],
description: 'Primary puppet construction material'
},
'Head Shape': {
type: 'select',
options: ['round', 'oval', 'angular', 'elongated', 'wide'],
description: 'Basic head shape geometry'
},
'Eye Type': {
type: 'select',
options: ['button', 'plastic', 'fabric', 'ping_pong', 'custom'],
description: 'Eye construction type'
},
'Eye Color': {
type: 'rich_text',
description: 'Specific eye color for consistency'
},
'Mouth Type': {
type: 'select',
options: ['basic_opening', 'articulated_jaw', 'simple_slit', 'complex_mechanical'],
description: 'Mouth mechanism type'
},
'Hair/Fur Type': {
type: 'select',
options: ['synthetic_hair', 'wool', 'fur_fabric', 'yarn', 'feathers', 'bald'],
description: 'Hair or fur material type'
},
'Hand Type': {
type: 'select',
options: ['simple_mittens', 'articulated_fingers', 'rod_controlled', 'glove_style'],
description: 'Hand construction and control method'
},
'Primary Color': {
type: 'rich_text',
description: 'Main character color for consistency'
},
'Secondary Color': {
type: 'rich_text',
description: 'Secondary character color'
},
'Special Markings': {
type: 'rich_text',
description: 'Unique markings, scars, patterns, or distinctive features'
},
'Clothing Description': {
type: 'rich_text',
description: 'Standard clothing or accessories'
}
},
// Movement and Mechanics
movementTraits: {
'Eye Movement': {
type: 'select',
options: ['fixed_position', 'limited_side_to_side', 'full_mechanical', 'blink_capable'],
description: 'Eye movement capabilities'
},
'Mouth Movement': {
type: 'select',
options: ['simple_open_close', 'jaw_articulation', 'tongue_visible', 'teeth_visible'],
description: 'Mouth movement mechanics'
},
'Head Movement': {
type: 'select',
options: ['basic_turn', 'full_rotation', 'tilt_capable', 'nod_shake'],
description: 'Head movement range'
},
'Body Movement': {
type: 'select',
options: ['static_pose', 'arm_articulation', 'torso_bend', 'full_puppeteer_control'],
description: 'Body movement capabilities'
},
'Hand Movement': {
type: 'select',
options: ['basic_positioning', 'finger_articulation', 'grip_capable', 'gesture_specific'],
description: 'Hand movement and manipulation'
},
'Movement Style': {
type: 'select',
options: ['bouncy_muppet', 'smooth_gliding', 'jerky_mechanical', 'flowing_graceful'],
description: 'Overall movement personality'
}
},
// Character Personality and Behavior
personalityTraits: {
'Energy Level': {
type: 'select',
options: ['low_energy', 'moderate', 'high_energy', 'hyperactive'],
description: 'Character energy and activity level'
},
'Character Archetype': {
type: 'select',
options: ['hero', 'comic_relief', 'wise_mentor', 'villain', 'innocent', 'quirky'],
description: 'Basic character role and archetype'
},
'Voice Match': {
type: 'select',
options: ['high_pitched', 'deep_resonant', 'raspy_textured', 'smooth_melodic'],
description: 'Voice characteristics for audio matching'
},
'Signature Gestures': {
type: 'rich_text',
description: 'Unique gestures or movements specific to character'
},
'Behavioral Quirks': {
type: 'rich_text',
description: 'Unique behavioral traits and mannerisms'
}
},
// Production and Technical
productionTraits: {
'Scale Reference Object': {
type: 'select',
options: ['coin', 'hand', 'smartphone', 'book', 'mug', 'ruler', 'doorframe', 'table', 'chair'],
description: 'Standard reference object for scale consistency'
},
'Lighting Setup': {
type: 'select',
options: ['studio_standard', 'dramatic_side', 'soft_diffused', 'high_contrast', 'theatrical'],
description: 'Preferred lighting setup for character'
},
'Camera Angle Preference': {
type: 'select',
options: ['straight_on', 'slight_low', 'slight_high', 'dynamic_angle'],
description: 'Best camera angle for character presentation'
},
'Background Preference': {
type: 'select',
options: ['solid_black', 'gradient_black', 'studio_backdrop', 'minimal_props'],
description: 'Background setup preference'
}
},
// Consistency and Quality Control
qualityControl: {
'Consistency Score': {
type: 'number',
description: 'Overall consistency rating (1-10) across productions'
},
'Last Updated': {
type: 'date',
description: 'Last time character traits were updated'
},
'Generation Count': {
type: 'number',
description: 'Number of times character has been generated'
},
'Quality Issues': {
type: 'multi_select',
options: ['scale_inconsistency', 'color_variation', 'feature_drift', 'construction_errors', 'lighting_mismatch'],
description: 'Tracked quality issues for improvement'
},
'Approved Variations': {
type: 'rich_text',
description: 'Approved variations from base character design'
}
}
};
}
// Generate character traits object from Notion page properties
extractCharacterTraits(notionPage) {
const properties = notionPage.properties;
const traits = {};
// Extract basic info
traits.name = this.extractText(properties['Character Name']);
traits.description = this.extractText(properties['Character Bio']);
// Extract physical traits
traits.size = this.extractSelect(properties['Character Size']);
traits.construction = this.extractSelect(properties['Construction Material']);
traits.headShape = this.extractSelect(properties['Head Shape']);
traits.eyeType = this.extractSelect(properties['Eye Type']);
traits.eyeColor = this.extractText(properties['Eye Color']);
traits.mouthType = this.extractSelect(properties['Mouth Type']);
traits.hairFur = this.extractSelect(properties['Hair/Fur Type']);
traits.handType = this.extractSelect(properties['Hand Type']);
traits.primaryColor = this.extractText(properties['Primary Color']);
traits.secondaryColor = this.extractText(properties['Secondary Color']);
traits.specialMarkings = this.extractText(properties['Special Markings']);
traits.clothing = this.extractText(properties['Clothing Description']);
// Extract movement traits
traits.eyeMovement = this.extractSelect(properties['Eye Movement']);
traits.mouthMovement = this.extractSelect(properties['Mouth Movement']);
traits.headMovement = this.extractSelect(properties['Head Movement']);
traits.bodyMovement = this.extractSelect(properties['Body Movement']);
traits.handMovement = this.extractSelect(properties['Hand Movement']);
traits.movementStyle = this.extractSelect(properties['Movement Style']);
// Extract personality traits
traits.energyLevel = this.extractSelect(properties['Energy Level']);
traits.archetype = this.extractSelect(properties['Character Archetype']);
traits.voiceMatch = this.extractSelect(properties['Voice Match']);
traits.signatureGestures = this.extractText(properties['Signature Gestures']);
traits.behavioralQuirks = this.extractText(properties['Behavioral Quirks']);
// Extract production traits
traits.scaleReference = this.extractSelect(properties['Scale Reference Object']);
traits.lightingSetup = this.extractSelect(properties['Lighting Setup']);
traits.cameraAngle = this.extractSelect(properties['Camera Angle Preference']);
traits.backgroundPreference = this.extractSelect(properties['Background Preference']);
return traits;
}
// Helper methods for extracting different property types
extractText(property) {
if (!property) return '';
if (property.rich_text && property.rich_text[0]) {
return property.rich_text[0].text.content;
}
if (property.title && property.title[0]) {
return property.title[0].text.content;
}
return '';
}
extractSelect(property) {
if (!property || !property.select) return '';
return property.select.name;
}
extractMultiSelect(property) {
if (!property || !property.multi_select) return [];
return property.multi_select.map(item => item.name);
}
extractNumber(property) {
if (!property || property.number === null) return 0;
return property.number;
}
// Create character with comprehensive traits
async createCharacterWithTraits(characterData, traits) {
const properties = {
// Basic character info
'Character Name': { title: [{ text: { content: characterData.name } }] },
'Character Bio': { rich_text: [{ text: { content: characterData.description } }] },
'Character Type': { select: { name: characterData.characterType || 'Main Character' } },
'Status': { select: { name: 'In Development' } },
// Physical traits
'Character Size': { select: { name: traits.size || 'medium' } },
'Construction Material': { select: { name: traits.construction || 'felt' } },
'Head Shape': { select: { name: traits.headShape || 'round' } },
'Eye Type': { select: { name: traits.eyeType || 'button' } },
'Eye Color': { rich_text: [{ text: { content: traits.eyeColor || 'brown' } }] },
'Mouth Type': { select: { name: traits.mouthType || 'basic_opening' } },
'Hair/Fur Type': { select: { name: traits.hairFur || 'synthetic_hair' } },
'Hand Type': { select: { name: traits.handType || 'simple_mittens' } },
'Primary Color': { rich_text: [{ text: { content: traits.primaryColor || 'brown' } }] },
'Secondary Color': { rich_text: [{ text: { content: traits.secondaryColor || 'white' } }] },
// Movement traits
'Movement Style': { select: { name: traits.movementStyle || 'bouncy_muppet' } },
'Eye Movement': { select: { name: traits.eyeMovement || 'fixed_position' } },
'Mouth Movement': { select: { name: traits.mouthMovement || 'simple_open_close' } },
// Personality traits
'Energy Level': { select: { name: traits.energyLevel || 'moderate' } },
'Character Archetype': { select: { name: traits.archetype || 'hero' } },
// Production traits
'Scale Reference Object': { select: { name: traits.scaleReference || 'hand' } },
'Lighting Setup': { select: { name: traits.lightingSetup || 'studio_standard' } },
'Background Preference': { select: { name: traits.backgroundPreference || 'solid_black' } },
// Quality control
'Generation Count': { number: 0 },
'Last Updated': { date: { start: new Date().toISOString().split('T')[0] } }
};
// Add optional fields if provided
if (traits.specialMarkings) {
properties['Special Markings'] = { rich_text: [{ text: { content: traits.specialMarkings } }] };
}
if (traits.clothing) {
properties['Clothing Description'] = { rich_text: [{ text: { content: traits.clothing } }] };
}
if (traits.signatureGestures) {
properties['Signature Gestures'] = { rich_text: [{ text: { content: traits.signatureGestures } }] };
}
if (traits.behavioralQuirks) {
properties['Behavioral Quirks'] = { rich_text: [{ text: { content: traits.behavioralQuirks } }] };
}
return properties;
}
// Update character generation count and consistency tracking
async updateCharacterUsage(characterId, qualityScore = null) {
const currentPage = await this.notion.pages.retrieve({ page_id: characterId });
const currentCount = this.extractNumber(currentPage.properties['Generation Count']);
const updateData = {
'Generation Count': { number: currentCount + 1 },
'Last Updated': { date: { start: new Date().toISOString().split('T')[0] } }
};
if (qualityScore !== null) {
updateData['Consistency Score'] = { number: qualityScore };
}
await this.notion.pages.update({
page_id: characterId,
properties: updateData
});
}
}