Skip to content

elizaos-plugins/plugin-wrapped

Repository files navigation

@elizaos/plugin-wrapped

Year-end wrapped experience - stats, story, achievements, and community belonging. A personalized reflection on the user's year with the agent.

Philosophy

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.

Design Decisions

Why Image Cards?

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]

Why Text Symbols (Not Emojis)?

Cards use text-based symbols (like "OvO" for Night Owl, "100" for Centurion) because:

  1. Font compatibility - The Inter font doesn't support emoji glyphs
  2. Consistent rendering - Works identically across all platforms
  3. Intentional aesthetic - Creates a unique, typographic look

Why Achievements?

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

Why Easter Eggs?

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.

Features

  • 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.

Example Cards

Here's what the wrapped cards look like:

Example wrapped card

Example wrapped card

Example wrapped card

Example wrapped card

Example wrapped card

Example wrapped card

Example wrapped card

Example wrapped card

Card System

Card Types (10 total)

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

Technical Implementation

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.

Installation

bun add @elizaos/plugin-wrapped

Usage

import { 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"

Output

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 (18 total)

Achievements are displayed on the Trophy card using text symbols (Inter font doesn't support emojis).

Tenure (Loyalty)

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

Activity (Engagement)

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

Time Patterns (Identity)

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

Engagement Style

Symbol Name Description Rarity
??? Curious Mind 200+ questions Uncommon
abc Storyteller Average 40+ words/message Uncommon

Community

Symbol Name Description Rarity
TOP Top Contributor Top 10% in room Rare
#1 Community Pillar Top 10% + 6mo tenure Epic

Consistency (Streaks)

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

Easter Eggs

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)

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                        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      │
                                 └────────────────────────────────┘

Card Generation Flow

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)      │
└─────────────────────────────────────┘

API

Plugin

import { wrappedPlugin } from '@elizaos/plugin-wrapped';

Stats Functions

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';

Card Components

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';

Types

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';

License

MIT

About

end of year fun

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published