score-virality
Analyze a clip's virality potential with scoring across multiple dimensions. Uses Web Worker for real-time scoring.
SKILL.mdAutoAnimation/.claude/skills/score-virality/SKILL.md
GitHubScore Virality
Analyze a ProAnimate clip's viral potential using both client-side heuristic scoring (instant, free) and AI-powered deep analysis (Gemini with Google Search grounding).
Purpose
Score a clip across multiple virality dimensions (hook strength, pacing, trend relevance, emotion, visual quality, rewatch value) to help creators optimize their content for maximum engagement. The system provides actionable improvement suggestions.
Steps
Understand the two scoring modes:
- Client-side heuristic (
viralityScoreWorker.ts): instant, free, runs in a Web Worker. Scores across 9 weighted factors totaling 0-100 points. - AI-powered deep analysis (
viralityScorer.ts): uses Gemini with Google Search grounding for trend matching. Costs credits. Returns per-dimension scores (0-100) and specific improvement suggestions. - Fast client analyzer (
viralityAnalyzer.ts): intermediate analysis with dimension-level scoring (hook, pacing, emotion, engagement, platform fit, shareability) computed from store data.
- Client-side heuristic (
Client-side scoring breakdown (max 100 points):
- Hook strength (0-15): text/CTA in first 3 seconds, opening visual present.
- Pacing (0-10): cuts/transitions detected (scene changes).
- Captions (0-10): captions enabled (any style except 'none').
- Audio (0-15): voice audio present + background music present.
- Aspect ratio (0-10): 9:16 for short-form platforms.
- Duration (0-10): optimal range 15-60 seconds.
- Text overlays (0-10): at least one text overlay present.
- Character animation (0-10): at least one character.
- B-roll / media variety (0-10): stock media or SVG objects present.
Gather clip metadata for scoring:
ClipMetadatainterface requires:durationSeconds,dialogueCount,characterCount,textOverlayCount,hasCTA,hasHook,captionStyle,aspectRatio,hasMusic,templateCount,svgObjectCount,stockMediaCount,topics[].- Extended fields:
hookStrengthFirstThreeSeconds(0-100),cutsPerMinute,averageLineDuration,hasOpeningVisual,trendKeywords[]. - Metadata is extracted from Zustand stores:
useMultiCharacterStore,useTextOverlayStore,useMediaStore,useHTMLTemplateLayerStore,useSVGObjectStore,useTimelineStore.
State hashing for change detection (
viralityStateHash.ts):computeProjectStateHash()computes a lightweight djb2 hash of project state.- Includes: dialogue count/text, overlay count/types, character count, duration, template IDs, media IDs.
- Re-scoring only triggers when the hash changes, avoiding unnecessary API calls.
- Hash is sub-millisecond performance.
Run AI-powered scoring (
viralityScorer.ts):scoreClipVirality(metadata, prompt)calls Gemini with the clip metadata.- Uses
responseMimeType: 'application/json'for structured output. - Enables
tools: [{ googleSearch: {} }]for real-time trend matching. - Returns:
overall(0-100),dimensions(hook, pacing, trend, emotion, visual, rewatch),suggestions[]. - Gated by credit system via
withCreditGate('virality-score', ...).
Run fast client analysis (
viralityAnalyzer.ts):ViralityAnalysisInputis gathered from stores.- Scores per dimension:
- Hook strength: penalizes generic openers ("hey", "welcome"), rewards questions, numbers, bold claims.
- Visual pacing: scene changes per 10 seconds (optimal 2-5), template usage, stock media presence.
- Emotional arc: emotion variety count (4+ is best), mood shift detection.
- Engagement: CTA presence, caption style, dialogue line count.
- Platform fit: aspect ratio and duration vs. platform requirements.
- Shareability: topic keywords analysis.
- Returns
ViralityAnalysiswith dimensions, improvements, and overall score.
Interpret improvement suggestions:
- Each
ViralityImprovementhas:dimension,priority,description,estimatedImpact. - Improvements are sorted by priority (highest impact first).
- Common suggestions: add a text hook in first 2 seconds, include trending topic reference, add CTA, increase visual variety.
- Each
Key Files
| Purpose | Path |
|---|---|
| Client-side heuristic scorer | src/services/viralityScoreWorker.ts |
| AI-powered scorer (Gemini) | src/services/viralityScorer.ts |
| Fast client analyzer | src/services/viralityAnalyzer.ts |
| State hash for change detection | src/services/viralityStateHash.ts |
| Virality types | src/types/virality.ts |
| Orchestrator ViralScore type | src/types/orchestrator.ts |
| Virality store | src/stores/useViralityStore.ts |
| Virality panel UI | src/components/panels/ViralityPanel.tsx |
| Virality score panel UI | src/components/panels/ViralityScorePanel.tsx |
| Auto virality score hook | src/hooks/useAutoViralityScore.ts |
| Server virality analysis | server/routes/viralityAnalysis.ts |
Common Issues
- Score always 0 or very low: The clip has minimal content. Check that dialogue, characters, and text overlays exist in the stores.
- State hash does not change: The hash only checks specific store fields. Adding a shape or changing a color may not trigger re-scoring.
- Gemini scoring fails: API key missing (
VITE_GEMINI_API_KEY) or quota exceeded. Falls back to client-side scoring. - Google Search grounding unavailable: Not available in all regions. The scorer still works without it but cannot match trending topics.
- Score seems inaccurate: Client-side heuristics are rule-based and cannot evaluate content quality. Use AI-powered scoring for nuanced analysis.
- Web Worker not responding: The Web Worker may have crashed. Check browser console for worker errors. Terminate and re-create the worker.
Examples
Run client-side scoring:
import { scoreClientSide } from '@/services/viralityScoreWorker'
const result = scoreClientSide({
durationSeconds: 30, dialogueCount: 5, characterCount: 1,
textOverlayCount: 2, hasCTA: true, hasHook: true,
captionStyle: 'word-by-word', aspectRatio: '9:16',
hasMusic: true, templateCount: 1, svgObjectCount: 0,
stockMediaCount: 2, topics: ['AI', 'productivity'],
hookStrengthFirstThreeSeconds: 80, cutsPerMinute: 6,
averageLineDuration: 3, hasOpeningVisual: true, trendKeywords: ['AI tools'],
})
console.log('Score:', result.score.overall, 'Factors:', result.factors)
Check if re-scoring is needed:
import { computeProjectStateHash } from '@/services/viralityStateHash'
const hash = computeProjectStateHash()
// Compare with previously stored hash to detect changes