Year-end wrapped experience - stats, story, achievements, and community belonging. A personalized reflection on the user's year with the agent.
This plugin is NOT a dashboard. It's a story.
Dashboards dump data. Stories create emotion. We want users to feel:
| Emotion | Example | Why It Matters |
|---|---|---|
| VALIDATED | "847 messages - that's a lot!" | Confirms their engagement was meaningful |
| NOSTALGIC | "Remember your first question?" | Creates emotional anchor to the past |
| PROUD | "You're in the Top 10%!" | Identity and social proof |
| BELONGING | "You contributed 4.2% of this room" | Part of something larger |
Every stat, every card, every achievement serves an emotional purpose.
The wrapped experience is delivered as beautiful PNG image cards that users can share on social media. Each card is designed to:
- Look premium - Dark mode, modern typography, generous whitespace
- Work everywhere - PNG format works on any platform
- Be shareable - Users are proud to post these
- Tell a story - Each card highlights ONE key insight
TEXT: "You sent 847 messages"
IMAGE CARD: [Beautiful PNG with 847 in giant typography, dark theme, your community name]
Cards use text-based symbols (like "OvO" for Night Owl, "100" for Centurion) because:
- Font compatibility - The Inter font doesn't support emoji glyphs
- Consistent rendering - Works identically across all platforms
- Intentional aesthetic - Creates a unique, typographic look
Achievements serve multiple purposes:
- Identity - "I'm a Night Owl" becomes part of self-concept
- Validation - Recognition for effort
- Aspiration - Locked badges create goals
- Shareability - "I got the legendary badge!" is social content
Easter eggs (42, 69, 420, 1337) reward attention and create shareable moments. They turn stats into stories. "I got 'The Answer'!" is a conversation starter.
- Image Cards - 10 beautiful PNG cards for social media sharing
- Personal Stats - Message counts, time patterns, streaks, records
- Achievements - 18 unlockable badges based on activity patterns
- Community Ranking - See where you stand (Top X%)
- Story Quotes - Your first message, late-night thoughts, evolution
- Archetypes - Night Owl, Question Machine, Weekend Warrior, etc.
Here's what the wrapped cards look like:
| Card | Purpose | Eligibility |
|---|---|---|
| Headline | Main stats (messages, conversations, streak) | Always |
| Rank | Community standing (TOP X%) | Top 25% only |
| Vibe | Archetype (Night Owl, Question Machine, etc.) | Clear pattern |
| Signature | Monthly activity "DNA" visualization | 50+ messages |
| Origin | First message quote | Safe quote exists |
| Evolution | Q1 vs Q4 quote comparison | Growth + quotes |
| 3AM | Late night quote | Safe late-night quote |
| Plot Twist | Unexpected stat (humor) | Interesting anomaly |
| Trophy | Achievement badges (with text symbols) | 2+ badges |
| Invitation | Community promo | Always |
Cards are rendered using:
- satori: JSX → SVG (React-like syntax)
- resvg: SVG → PNG (Rust-based, high quality)
- Inter font: Clean typography (text symbols instead of emojis)
- Base64 data URLs: Converted to buffers for Discord attachments
// All cards sent in a single message
await callback({
text: '✨ Your 2024 Wrapped ✨\n\n847 messages · 156 conversations · 23 day streak',
attachments: cards.map(card => ({
url: card.dataUrl,
contentType: ContentType.IMAGE
}))
});Note: Base64 image data is filtered from memory storage to prevent context bloat in subsequent LLM calls.
bun add @elizaos/plugin-wrappedimport { wrappedPlugin } from '@elizaos/plugin-wrapped';
const agent = {
plugins: [wrappedPlugin],
};Users can trigger wrapped with phrases like:
- "show me my wrapped"
- "what was our year like"
- "give me my year in review"
- "how much have we talked"
- "my stats"
The wrapped action sends a brief text summary followed by all eligible image cards as attachments:
✨ Your 2024 Wrapped ✨
847 messages · 156 conversations · 23 day streak
[Headline Card - PNG]
[Rank Card - PNG]
[Vibe Card - PNG]
[Trophy Card - PNG]
...
Each card is a standalone shareable image that users can save and post to social media.
Achievements are displayed on the Trophy card using text symbols (Inter font doesn't support emojis).
| Symbol | Name | Description | Rarity |
|---|---|---|---|
| 365 | Year One | Been here 365+ days | Uncommon |
| * | Early Adopter | Joined in first 30 days | Rare |
| #1 | Founding Member | One of first 10 in room | Legendary |
| Symbol | Name | Description | Rarity |
|---|---|---|---|
| ... | Conversation Starter | 50+ conversations | Common |
| >> | Deep Diver | 10+ deep conversations | Uncommon |
| 100 | Centurion | 100+ messages in one month | Rare |
| 50+ | Marathon | 50+ message conversation | Rare |
| Symbol | Name | Description | Rarity |
|---|---|---|---|
| OvO | Night Owl | 50+ messages after midnight | Uncommon |
| ^v^ | Early Bird | 50+ messages before 8am | Uncommon |
| S+S | Weekend Warrior | 60%+ on weekends | Uncommon |
| zzZ | Night Shift | 100+ messages 12am-5am | Epic |
| Symbol | Name | Description | Rarity |
|---|---|---|---|
| ??? | Curious Mind | 200+ questions | Uncommon |
| abc | Storyteller | Average 40+ words/message | Uncommon |
| Symbol | Name | Description | Rarity |
|---|---|---|---|
| TOP | Top Contributor | Top 10% in room | Rare |
| #1 | Community Pillar | Top 10% + 6mo tenure | Epic |
| Symbol | Name | Description | Rarity |
|---|---|---|---|
| 7d | Streak Starter | 7+ day streak | Common |
| 20d | Streak Master | 20+ day streak | Uncommon |
| 100d | The Streak | 100+ day streak | Legendary |
The plugin detects special numbers and patterns:
- Nice. - Exactly 69 messages in a month
- The Answer - 42-day streak (Hitchhiker's Guide reference)
- Blaze It - Exactly 420 messages
- L33T - 1337 messages
- Palindrome - Message count reads the same backwards (e.g., 121)
┌─────────────────────────────────────────────────────────────────┐
│ ACTION LAYER │
│ GET_WRAPPED action: collect data → generate cards → send │
└────────────────────────────┬────────────────────────────────────┘
│
┌───────────────────┴───────────────────┐
▼ ▼
┌────────────────────────────┐ ┌────────────────────────────────┐
│ DATA LAYER │ │ CARD LAYER │
│ │ │ │
│ collector.ts - Raw msgs │ │ generator.ts - PNG rendering │
│ personal.ts - User stats │ │ selector.ts - Eligibility │
│ community.ts - Rankings │ │ quotes.ts - Safe quotes │
│ growth.ts - Evolution │ │ fonts.ts - Inter font │
│ streaks.ts - Streaks │ │ │
│ │ │ designs/ │
└────────────────────────────┘ │ headline.tsx - Stats │
│ rank.tsx - TOP X% │
│ trophy.tsx - Badges │
│ vibe.tsx - Archetype │
│ signature.tsx - DNA viz │
│ origin.tsx - First msg │
│ evolution.tsx - Q1 vs Q4 │
│ threeAm.tsx - Late night │
│ plotTwist.tsx - Humor │
│ invitation.tsx- Promo │
│ base.tsx - Shared │
└────────────────────────────────┘
USER DATA (PersonalStats, StreakData, etc.)
│
▼
┌─────────────────────────────────────┐
│ ELIGIBILITY CHECK │
│ selector.ts: Which cards qualify? │
│ │
│ • Has enough messages? │
│ • In top 25%? │
│ • Safe quotes available? │
│ • Interesting anomaly found? │
└─────────────────┬───────────────────┘
│
▼
┌─────────────────────────────────────┐
│ CARD GENERATION │
│ │
│ For each eligible card: │
│ 1. Create JSX component │
│ 2. satori: JSX → SVG (Inter font) │
│ 3. resvg: SVG → PNG Buffer │
│ 4. Convert to Base64 data URL │
└─────────────────┬───────────────────┘
│
▼
┌─────────────────────────────────────┐
│ SINGLE MESSAGE │
│ │
│ Brief text summary + │
│ All cards as attachments │
│ (Base64 filtered from memory) │
└─────────────────────────────────────┘
import { wrappedPlugin } from '@elizaos/plugin-wrapped';import {
collectUserMessages, // Get all messages for a user
computePersonalStats, // Calculate personal metrics
computeStreaks, // Calculate streak data
computeCommunityStats, // Calculate room rankings
computeGrowthStats, // Compare Q1 to Q4
evaluateAchievements, // Check which badges earned
} from '@elizaos/plugin-wrapped';import {
// Core rendering
renderCard, // Render JSX to PNG buffer
// Card components (JSX)
HeadlineCard, // Main stats card
RankCard, // Community ranking card
TrophyCard, // Achievements card (text symbols)
VibeCard, // Archetype card
SignatureCard, // Activity DNA card
OriginCard, // First message card
EvolutionCard, // Q1 vs Q4 card
ThreeAmCard, // Late night card
PlotTwistCard, // Humor card
InvitationCard, // Promo card
// Eligibility
checkCardEligibility, // Check which cards user qualifies for
// Quote safety
isQuoteSafe, // Check if text is safe to share
} from '@elizaos/plugin-wrapped';import type {
PersonalStats, // User's message stats
StreakData, // Streak information
CommunityStats, // Room rankings
GrowthStats, // Q1 vs Q4 comparison
Achievement, // Badge definition
AchievementResult, // Badge evaluation result
WrappedData, // Complete wrapped bundle
RenderedCard, // { buffer, width, height, dataUrl }
} from '@elizaos/plugin-wrapped';MIT







